diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index aad202a..3aae2d6 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -10,7 +10,13 @@ import type {HeapOptions} from '../types'; export class HeapItem { + constructor(priority: number = NaN, val: T | null = null) { + this._val = val; + this._priority = priority; + } + private _priority: number; + get priority(): number { return this._priority; } @@ -20,6 +26,7 @@ export class HeapItem { } private _val: T | null; + get val(): T | null { return this._val; } @@ -27,11 +34,6 @@ export class HeapItem { set val(value: T | null) { this._val = value; } - - constructor(priority: number = NaN, val: T | null = null) { - this._val = val; - this._priority = priority; - } } export abstract class Heap { @@ -176,7 +178,7 @@ export abstract class Heap { * @param {T | HeapItem} node - The parameter `node` can be of type `T` or `HeapItem`. * @returns a boolean value. */ - has(node:T | HeapItem): boolean { + has(node: T | HeapItem): boolean { if (node instanceof HeapItem) { return this.getPq().getNodes().includes(node); } else { diff --git a/src/data-structures/index.ts b/src/data-structures/index.ts index 6957d45..c431497 100644 --- a/src/data-structures/index.ts +++ b/src/data-structures/index.ts @@ -4,6 +4,7 @@ export * from './stack'; export * from './queue'; export * from './graph'; export * from './binary-tree'; +export * from './tree'; export * from './heap'; export * from './priority-queue'; export * from './matrix'; diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index fb764d1..d123353 100644 --- a/src/data-structures/priority-queue/max-priority-queue.ts +++ b/src/data-structures/priority-queue/max-priority-queue.ts @@ -6,19 +6,43 @@ * @license MIT License */ import {PriorityQueue} from './priority-queue'; -import type {PriorityQueueOptions} from '../types'; +import type {PriorityQueueOptions, SpecifyOptional} from '../types'; export class MaxPriorityQueue extends PriorityQueue { + constructor(options?: Omit, 'comparator'>) + constructor(options: PriorityQueueOptions) /** - * The constructor initializes a PriorityQueue with optional nodes and a comparator function. - * @param [options] - An optional object that contains the following properties: + * The constructor initializes a priority queue with an optional comparator function. + * @param [options] - The `options` parameter is an optional object that can contain various properties to configure + * the priority queue. */ - constructor(options?: PriorityQueueOptions) { + constructor(options?: SpecifyOptional, 'comparator'>) { super({ - nodes: options?.nodes, comparator: options?.comparator ? options.comparator : (a: T, b: T) => { + ...options, + comparator: options?.comparator ? options.comparator : (a: T, b: T) => { const aKey = a as unknown as number, bKey = b as unknown as number; return bKey - aKey; } }); } + + static override heapify(options?: Omit, 'comparator'>): MaxPriorityQueue + static override heapify(options: PriorityQueueOptions): MaxPriorityQueue + /** + * The function `heapify` creates a max priority queue from the given options and returns it. + * @param options - The `options` parameter is an object that contains configuration options for creating a priority + * queue. It can have the following properties: + * @returns a MaxPriorityQueue object. + */ + static override heapify(options: PriorityQueueOptions): MaxPriorityQueue { + const maxPQ = new MaxPriorityQueue({ + ...options, + comparator: options?.comparator ? options.comparator : (a: T, b: T) => { + const aKey = a as unknown as number, bKey = b as unknown as number; + return bKey - aKey; + } + }); + maxPQ._fix(); + return maxPQ; + } } \ No newline at end of file diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 6e84308..bd01c70 100644 --- a/src/data-structures/priority-queue/min-priority-queue.ts +++ b/src/data-structures/priority-queue/min-priority-queue.ts @@ -6,19 +6,44 @@ * @license MIT License */ import {PriorityQueue} from './priority-queue'; -import type {PriorityQueueOptions} from '../types'; +import type {PriorityQueueOptions, SpecifyOptional} from '../types'; export class MinPriorityQueue extends PriorityQueue { + constructor(options?: Omit, 'comparator'>) + constructor(options: PriorityQueueOptions) /** - * The constructor initializes a PriorityQueue with optional nodes and a comparator function. - * @param [options] - An optional object that contains the following properties: + * The constructor initializes a priority queue with an optional comparator function. + * @param [options] - The `options` parameter is an optional object that can contain various configuration options for + * the `PriorityQueue` constructor. */ - constructor(options?: PriorityQueueOptions) { + constructor(options?: SpecifyOptional, 'comparator'>) { super({ - nodes: options?.nodes, comparator: options?.comparator ? options.comparator : (a: T, b: T) => { + ...options, + comparator: options?.comparator ? options.comparator : (a: T, b: T) => { const aKey = a as unknown as number, bKey = b as unknown as number; return aKey - bKey; } }); } + + static override heapify(options?: Omit, 'comparator'>): MinPriorityQueue + static override heapify(options: PriorityQueueOptions): MinPriorityQueue + /** + * The function `heapify` creates a new MinPriorityQueue instance and sets the comparator function based on the options + * provided, and then fixes the heap structure of the queue. + * @param options - The `options` parameter is an object that contains configuration options for creating a priority + * queue. It can have the following properties: + * @returns a MinPriorityQueue object. + */ + static override heapify(options: PriorityQueueOptions): MinPriorityQueue { + const minPQ = new MinPriorityQueue({ + ...options, + comparator: options?.comparator ? options.comparator : (a: T, b: T) => { + const aKey = a as unknown as number, bKey = b as unknown as number; + return aKey - bKey; + } + }); + minPQ._fix(); + return minPQ; + } } \ No newline at end of file diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 90cc87c..ec6632e 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -8,6 +8,22 @@ import type {PriorityQueueComparator, PriorityQueueDFSOrderPattern, PriorityQueueOptions} from '../types'; export class PriorityQueue { + /** + * The constructor initializes a priority queue with the given options, including an array of nodes and a comparator + * function. + * @param options - The `options` parameter is an object that contains the following properties: + */ + constructor(options: PriorityQueueOptions) { + const {nodes, comparator, isFix = true} = options; + this._comparator = comparator; + + if (nodes && Array.isArray(nodes) && nodes.length > 0) { + // TODO support distinct + this._nodes = [...nodes]; + isFix && this._fix(); + } + } + protected _nodes: T[] = []; get nodes(): T[] { @@ -21,22 +37,30 @@ export class PriorityQueue { get size(): number { return this.nodes.length; } - /** - * The constructor initializes a priority queue with the given options, including an array of nodes and a comparator - * function. - * @param options - The `options` parameter is an object that contains the following properties: - */ - constructor(options: PriorityQueueOptions) { - const {nodes, comparator, isFix = true} = options; - this._comparator = comparator; - if (nodes && nodes instanceof Array && nodes.length > 0) { - // TODO support distinct - this._nodes = Array.isArray(nodes) ? [...nodes] : []; - isFix && this._fix(); - } + /** + * The `heapify` function creates a new PriorityQueue instance and fixes the heap property. + * @param options - The "options" parameter is an object that contains the configuration options for the PriorityQueue. + * It can include properties such as "comparator" which specifies the comparison function used to order the elements in + * the priority queue, and "initialValues" which is an array of initial values to be added to the priority + * @returns a new instance of the PriorityQueue class after performing the heapify operation on it. + */ + static heapify(options: PriorityQueueOptions) { + const heap = new PriorityQueue(options); + heap._fix(); + return heap; } + /** + * The function checks if a priority queue is valid by creating a new priority queue with a fix option and then calling + * the isValid method. + * @param options - An object containing options for creating a priority queue. The options object should have the + * following properties: + * @returns the result of calling the `isValid()` method on a new instance of the `PriorityQueue` class. + */ + static isPriorityQueueified(options: Omit, 'isFix'>) { + return new PriorityQueue({...options, isFix: false}).isValid(); + } /** * Starting from TypeScript version 5.0 and onwards, the use of distinct access modifiers for Getters and Setters is not permitted. As an alternative, to ensure compatibility, it is necessary to adopt a Java-style approach for Setters (using the same name as the property) while utilizing separate method names for Getters. @@ -134,7 +158,78 @@ export class PriorityQueue { return new PriorityQueue({nodes: this.nodes, comparator: this._comparator}); } + // --- start additional methods --- + /** + * The `isValid` function recursively checks if a binary tree satisfies a certain condition. + * @returns The function `isValid()` returns a boolean value. + */ + isValid(): boolean { + for (let i = 0; i < this.nodes.length; i++) { + const leftChildIndex = this._getLeft(i); + const rightChildIndex = this._getRight(i); + if (this._isValidIndex(leftChildIndex) && !this._compare(leftChildIndex, i)) { + return false; + } + if (this._isValidIndex(rightChildIndex) && !this._compare(rightChildIndex, i)) { + return false; + } + } + return true; + } + /** + * Plan to support sorting of duplicate elements. + */ + /** + * The function sorts the elements in a data structure and returns them in an array. + * Plan to support sorting of duplicate elements. + * @returns The `sort()` method is returning an array of type `T[]`. + */ + sort(): T[] { + // TODO Plan to support sorting of duplicate elements. + const visitedNode: T[] = []; + while (this.size !== 0) { + const top = this.poll(); + if (top) visitedNode.push(top); + } + return visitedNode; + } + + /** + * The DFS function performs a depth-first search traversal on a binary tree and returns an array of visited nodes + * based on the specified traversal order. + * @param {PriorityQueueDFSOrderPattern} dfsMode - The dfsMode parameter is a string that specifies the order in which + * the nodes should be visited during the Depth-First Search (DFS) traversal. It can have one of the following values: + * @returns an array of type `(T | null)[]`. + */ + DFS(dfsMode: PriorityQueueDFSOrderPattern): (T | null)[] { + const visitedNode: (T | null)[] = []; + + const traverse = (cur: number) => { + const leftChildIndex = this._getLeft(cur); + const rightChildIndex = this._getRight(cur); + switch (dfsMode) { + case 'in': + this._isValidIndex(leftChildIndex) && traverse(leftChildIndex); + visitedNode.push(this.nodes[cur] ?? null); + this._isValidIndex(rightChildIndex) && traverse(rightChildIndex); + break; + case 'pre': + visitedNode.push(this.nodes[cur] ?? null); + this._isValidIndex(leftChildIndex) && traverse(leftChildIndex); + this._isValidIndex(rightChildIndex) && traverse(rightChildIndex); + break; + case 'post': + this._isValidIndex(leftChildIndex) && traverse(leftChildIndex); + this._isValidIndex(rightChildIndex) && traverse(rightChildIndex); + visitedNode.push(this.nodes[cur] ?? null); + break; + } + }; + + this._isValidIndex(0) && traverse(0); + return visitedNode; + } protected readonly _comparator: PriorityQueueComparator = (a: T, b: T) => { const aKey = a as unknown as number, bKey = b as unknown as number; @@ -255,105 +350,5 @@ export class PriorityQueue { for (let i = Math.floor(this.size / 2); i > -1; i--) this._heapifyDown(i); } - // --- start additional methods --- - /** - * The `isValid` function recursively checks if a binary tree satisfies a certain condition. - * @returns The function `isValid()` returns a boolean value. - */ - isValid(): boolean { - const isValidRecursive = (parentIndex: number): boolean => { - let isValidLeft = true; - let isValidRight = true; - - if (this._getLeft(parentIndex) !== -1) { - const leftChildIndex = (parentIndex * 2) + 1; - if (!this._compare(parentIndex, leftChildIndex)) return false; - isValidLeft = isValidRecursive(leftChildIndex); - } - - if (this._getRight(parentIndex) !== -1) { - const rightChildIndex = (parentIndex * 2) + 2; - if (!this._compare(parentIndex, rightChildIndex)) return false; - isValidRight = isValidRecursive(rightChildIndex); - } - - return isValidLeft && isValidRight; - }; - - return isValidRecursive(0); - } - - /** - * The function sorts the elements in a data structure and returns them in ascending order. - * @returns The `sort()` function is returning an array of type `T[]`. - */ - sort(): T[] { - const visitedNode: T[] = []; - while (this.size !== 0) { - const top = this.poll(); - if (top) visitedNode.push(top); - } - return visitedNode; - } - - /** - * The DFS function performs a depth-first search traversal on a binary tree and returns an array of visited nodes - * based on the specified traversal order. - * @param {PriorityQueueDFSOrderPattern} dfsMode - The dfsMode parameter is a string that specifies the order in which - * the nodes should be visited during the Depth-First Search (DFS) traversal. It can have one of the following values: - * @returns an array of type `(T | null)[]`. - */ - DFS(dfsMode: PriorityQueueDFSOrderPattern): (T | null)[] { - const visitedNode: (T | null)[] = []; - - const traverse = (cur: number) => { - const leftChildIndex = this._getLeft(cur); - const rightChildIndex = this._getRight(cur); - switch (dfsMode) { - case 'in': - this._isValidIndex(leftChildIndex) && traverse(leftChildIndex); - visitedNode.push(this.nodes[cur] ?? null); - this._isValidIndex(rightChildIndex) && traverse(rightChildIndex); - break; - case 'pre': - visitedNode.push(this.nodes[cur] ?? null); - this._isValidIndex(leftChildIndex) && traverse(leftChildIndex); - this._isValidIndex(rightChildIndex) && traverse(rightChildIndex); - break; - case 'post': - this._isValidIndex(leftChildIndex) && traverse(leftChildIndex); - this._isValidIndex(rightChildIndex) && traverse(rightChildIndex); - visitedNode.push(this.nodes[cur] ?? null); - break; - } - }; - - this._isValidIndex(0) && traverse(0); - return visitedNode; - } - /** - * The `heapify` function creates a new PriorityQueue instance and fixes the heap property. - * @param options - The "options" parameter is an object that contains the configuration options for the PriorityQueue. - * It can include properties such as "comparator" which specifies the comparison function used to order the elements in - * the priority queue, and "initialValues" which is an array of initial values to be added to the priority - * @returns a new instance of the PriorityQueue class after performing the heapify operation on it. - */ - static heapify(options: PriorityQueueOptions) { - const heap = new PriorityQueue(options); - heap._fix(); - return heap; - } - - /** - * The function checks if a priority queue is valid by creating a new priority queue with a fix option and then calling - * the isValid method. - * @param options - An object containing options for creating a priority queue. The options object should have the - * following properties: - * @returns the result of calling the `isValid()` method on a new instance of the `PriorityQueue` class. - */ - static isPriorityQueueified(options: Omit, 'isFix'>) { - return new PriorityQueue({...options, isFix: true}).isValid(); - } - // --- end additional methods --- } \ No newline at end of file diff --git a/src/data-structures/tree/index.ts b/src/data-structures/tree/index.ts new file mode 100644 index 0000000..a6c9ec8 --- /dev/null +++ b/src/data-structures/tree/index.ts @@ -0,0 +1 @@ +export * from './tree'; \ No newline at end of file diff --git a/src/data-structures/tree/tree.ts b/src/data-structures/tree/tree.ts new file mode 100644 index 0000000..40b4ff2 --- /dev/null +++ b/src/data-structures/tree/tree.ts @@ -0,0 +1,54 @@ +export class TreeNode { + id: string; + name?: string | undefined; + value?: T | undefined; + children?: TreeNode[] | undefined; + + constructor(id: string, name?: string, value?: T, children?: TreeNode[]) { + this.id = id; + this.name = name || ''; + this.value = value || undefined; + this.children = children || []; + } + + // TODO get set + // get name (): string | undefined { + // return this.name; + // } + // + // set name (name: string | undefined) { + // this.name = name; + // } + + addChildren(children: TreeNode | TreeNode []) { + if (!this.children) { + this.children = []; + } + if (children instanceof TreeNode) { + this.children.push(children); + } else { + this.children = this.children.concat(children); + } + } + + getHeight() { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const beginRoot = this; + let maxDepth = 1; + if (beginRoot) { + const bfs = (node: TreeNode, level: number) => { + if (level > maxDepth) { + maxDepth = level; + } + const {children} = node; + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + bfs(children[i], level + 1); + } + } + }; + bfs(beginRoot, 1); + } + return maxDepth; + } +} \ No newline at end of file diff --git a/src/utils/types/utils.ts b/src/utils/types/utils.ts index 37d3ea3..dc1f129 100644 --- a/src/utils/types/utils.ts +++ b/src/utils/types/utils.ts @@ -1,4 +1,6 @@ export type ToThunkFn = () => ReturnType; export type Thunk = () => ReturnType & { __THUNK__: Symbol }; export type TrlFn = (...args: any[]) => any; -export type TrlAsyncFn = (...args: any[]) => any; \ No newline at end of file +export type TrlAsyncFn = (...args: any[]) => any; + +export type SpecifyOptional = Omit & Partial>; diff --git a/tests/unit/data-structures/graph/directed-graph.test.ts b/tests/unit/data-structures/graph/directed-graph.test.ts index 5554814..988264e 100644 --- a/tests/unit/data-structures/graph/directed-graph.test.ts +++ b/tests/unit/data-structures/graph/directed-graph.test.ts @@ -65,33 +65,37 @@ describe('DirectedGraph Test1', () => { class MyVertex extends DirectedVertex { - private _data: string; - get data(): string { - return this._data; - } - set data(value: string) { - this._data = value; - } - constructor(id: VertexId, data: string) { super(id); this._data = data; } -} -class MyEdge extends DirectedEdge { private _data: string; + get data(): string { return this._data; } + set data(value: string) { this._data = value; } +} +class MyEdge extends DirectedEdge { constructor(v1: VertexId, v2: VertexId, weight: number, data: string) { super(v1, v2, weight); this._data = data; } + + private _data: string; + + get data(): string { + return this._data; + } + + set data(value: string) { + this._data = value; + } } diff --git a/tests/unit/data-structures/graph/undirected-graph.ts b/tests/unit/data-structures/graph/undirected-graph.ts index b1a37c0..48f510e 100644 --- a/tests/unit/data-structures/graph/undirected-graph.ts +++ b/tests/unit/data-structures/graph/undirected-graph.ts @@ -1,5 +1,3 @@ -import {DirectedEdge, DirectedGraph, DirectedVertex} from '../../../../src'; - describe('UndirectedGraph Test1', () => { }); diff --git a/tests/unit/data-structures/heap/heap.test.ts b/tests/unit/data-structures/heap/heap.test.ts index 485b954..f058a6c 100644 --- a/tests/unit/data-structures/heap/heap.test.ts +++ b/tests/unit/data-structures/heap/heap.test.ts @@ -1,117 +1,5 @@ -import {HeapItem, MaxHeap, MinHeap} from '../../../../src'; - describe('Heap Test1', () => { - it('should numeric Min Heap operations be proper', function () { - const minNumHeap = new MinHeap(); - expect(minNumHeap).toBeInstanceOf(MinHeap); - - minNumHeap.add(1); - expect(minNumHeap.has(1)).toBe(true); - minNumHeap.add(6); - expect(minNumHeap.has(2)).toBe(false); - expect(minNumHeap.has(6)).toBe(true); - minNumHeap.add(2); - expect(minNumHeap.has(2)).toBe(true); - minNumHeap.add(0); - expect(minNumHeap.has(0)).toBe(true); - minNumHeap.add(5); - expect(minNumHeap.has(5)).toBe(true); - minNumHeap.add(9); - expect(minNumHeap.has(9)).toBe(true); - expect(minNumHeap.size).toBe(6); - - const poll1 = minNumHeap.poll(); - expect(poll1).toBeInstanceOf(HeapItem) - poll1 instanceof HeapItem && expect(poll1.val).toBe(0); - - const poll2 = minNumHeap.poll(); - expect(poll2).toBeInstanceOf(HeapItem) - poll2 instanceof HeapItem && expect(poll2.val).toBe(1); - - const peek1 = minNumHeap.peek(); - expect(peek1).toBeInstanceOf(HeapItem) - peek1 instanceof HeapItem && expect(peek1.val).toBe(2); - - const heapArray = minNumHeap.toArray(); - expect(heapArray).toBeInstanceOf(Array); - expect(heapArray.map(item => item.priority)).toEqual([2, 5, 9, 6]); - expect(minNumHeap.size).toBe(4); - }); - - it('should object Max Heap operations be proper', function () { - const maxHeap = new MaxHeap<{ keyA: string }>(); - const myObj1 = {keyA: 'a1'}, myObj6 = {keyA: 'a6'}, myObj5 = {keyA: 'a5'}, myObj2 = {keyA: 'a2'}, - myObj0 = {keyA: 'a0'}, myObj9 = {keyA: 'a9'}; - maxHeap.add(myObj1, 1); - expect(maxHeap.has(myObj1)).toBe(true); - expect(maxHeap.has(myObj9)).toBe(false); - maxHeap.add(myObj6, 6); - expect(maxHeap.has(myObj6)).toBe(true); - maxHeap.add(myObj5, 5); - expect(maxHeap.has(myObj5)).toBe(true); - maxHeap.add(myObj2, 2); - expect(maxHeap.has(myObj2)).toBe(true); - expect(maxHeap.has(myObj6)).toBe(true); - maxHeap.add(myObj0, 0); - expect(maxHeap.has(myObj0)).toBe(true); - expect(maxHeap.has(myObj9)).toBe(false); - maxHeap.add(myObj9, 9); - expect(maxHeap.has(myObj9)).toBe(true); - - const peek9 = maxHeap.peek(); - peek9 && peek9.val && expect(peek9.val.keyA).toBe('a9'); - - const heapToArr = maxHeap.toArray(); - expect(heapToArr.map(item => item.val?.keyA)).toEqual(['a9', 'a2', 'a6', 'a1', 'a0', 'a5']); - - const values = ['a9', 'a6', 'a5', 'a2', 'a1', 'a0']; - let i = 0; - while (maxHeap.size > 0) { - const polled = maxHeap.poll(); - expect(polled).toBeInstanceOf(HeapItem<{ keyA: string }>); - polled && expect(polled.val).toHaveProperty('keyA'); - polled && polled.val && expect(polled.val.keyA).toBe(values[i]); - i++; - } - }); - - it('should object Min Heap operations be proper', function () { - class MyObject { - keyA: string; - - constructor(keyA: string) { - this.keyA = keyA; - } - } - - const minObjHeap = new MinHeap(); - - const obj1 = new MyObject('a1'), obj6 = new MyObject('a6'), obj2 = new MyObject('a2'), - obj0 = new MyObject('a0'); - minObjHeap.add(obj1, 1); - expect(minObjHeap.has(obj1)).toBe(true); - expect(minObjHeap.has(obj6)).toBe(false); - minObjHeap.add(obj6, 6); - expect(minObjHeap.has(obj6)).toBe(true); - minObjHeap.add(obj2, 2); - expect(minObjHeap.has(obj2)).toBe(true); - minObjHeap.add(obj0, 0); - expect(minObjHeap.has(obj0)).toBe(true); - - const peek = minObjHeap.peek(); - peek && peek.val && expect(peek.val.keyA).toBe('a0'); - - const heapToArr = minObjHeap.toArray(); - expect(heapToArr.map(item => item.val?.keyA)).toEqual(['a0', 'a1', 'a2', 'a6']); - - const values = ['a0', 'a1', 'a2', 'a6']; - let i = 0; - while (minObjHeap.size > 0) { - const polled = minObjHeap.poll(); - expect(polled).toBeInstanceOf(HeapItem); - polled && expect(polled.val).toBeInstanceOf(MyObject); - polled && polled.val && expect(polled.val.keyA).toBe(values[i]); - i++; - } + it('should xxx', function () { + expect(true).toBe(true); }); }); \ No newline at end of file diff --git a/tests/unit/data-structures/heap/index.ts b/tests/unit/data-structures/heap/index.ts deleted file mode 100644 index 8c22c67..0000000 --- a/tests/unit/data-structures/heap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './heap.test'; diff --git a/tests/unit/data-structures/heap/max-heap.test.ts b/tests/unit/data-structures/heap/max-heap.test.ts new file mode 100644 index 0000000..96045c6 --- /dev/null +++ b/tests/unit/data-structures/heap/max-heap.test.ts @@ -0,0 +1,42 @@ +import {HeapItem, MaxHeap} from '../../../../src'; + +describe('MaxHeap Test1', () => { + + it('should object Max Heap operations be proper', function () { + const maxHeap = new MaxHeap<{ keyA: string }>(); + const myObj1 = {keyA: 'a1'}, myObj6 = {keyA: 'a6'}, myObj5 = {keyA: 'a5'}, myObj2 = {keyA: 'a2'}, + myObj0 = {keyA: 'a0'}, myObj9 = {keyA: 'a9'}; + maxHeap.add(myObj1, 1); + expect(maxHeap.has(myObj1)).toBe(true); + expect(maxHeap.has(myObj9)).toBe(false); + maxHeap.add(myObj6, 6); + expect(maxHeap.has(myObj6)).toBe(true); + maxHeap.add(myObj5, 5); + expect(maxHeap.has(myObj5)).toBe(true); + maxHeap.add(myObj2, 2); + expect(maxHeap.has(myObj2)).toBe(true); + expect(maxHeap.has(myObj6)).toBe(true); + maxHeap.add(myObj0, 0); + expect(maxHeap.has(myObj0)).toBe(true); + expect(maxHeap.has(myObj9)).toBe(false); + maxHeap.add(myObj9, 9); + expect(maxHeap.has(myObj9)).toBe(true); + + const peek9 = maxHeap.peek(); + peek9 && peek9.val && expect(peek9.val.keyA).toBe('a9'); + + const heapToArr = maxHeap.toArray(); + expect(heapToArr.map(item => item.val?.keyA)).toEqual(['a9', 'a2', 'a6', 'a1', 'a0', 'a5']); + + const values = ['a9', 'a6', 'a5', 'a2', 'a1', 'a0']; + let i = 0; + while (maxHeap.size > 0) { + const polled = maxHeap.poll(); + expect(polled).toBeInstanceOf(HeapItem<{ keyA: string }>); + polled && expect(polled.val).toHaveProperty('keyA'); + polled && polled.val && expect(polled.val.keyA).toBe(values[i]); + i++; + } + }); + +}); \ No newline at end of file diff --git a/tests/unit/data-structures/heap/min-heap.test.ts b/tests/unit/data-structures/heap/min-heap.test.ts new file mode 100644 index 0000000..a4930f0 --- /dev/null +++ b/tests/unit/data-structures/heap/min-heap.test.ts @@ -0,0 +1,80 @@ +import {HeapItem, MinHeap} from '../../../../src'; + +describe('MinHeap Test1', () => { + it('should numeric Min Heap operations be proper', function () { + const minNumHeap = new MinHeap(); + expect(minNumHeap).toBeInstanceOf(MinHeap); + + minNumHeap.add(1); + expect(minNumHeap.has(1)).toBe(true); + minNumHeap.add(6); + expect(minNumHeap.has(2)).toBe(false); + expect(minNumHeap.has(6)).toBe(true); + minNumHeap.add(2); + expect(minNumHeap.has(2)).toBe(true); + minNumHeap.add(0); + expect(minNumHeap.has(0)).toBe(true); + minNumHeap.add(5); + expect(minNumHeap.has(5)).toBe(true); + minNumHeap.add(9); + expect(minNumHeap.has(9)).toBe(true); + expect(minNumHeap.size).toBe(6); + + const poll1 = minNumHeap.poll(); + expect(poll1).toBeInstanceOf(HeapItem) + poll1 instanceof HeapItem && expect(poll1.val).toBe(0); + + const poll2 = minNumHeap.poll(); + expect(poll2).toBeInstanceOf(HeapItem) + poll2 instanceof HeapItem && expect(poll2.val).toBe(1); + + const peek1 = minNumHeap.peek(); + expect(peek1).toBeInstanceOf(HeapItem) + peek1 instanceof HeapItem && expect(peek1.val).toBe(2); + + const heapArray = minNumHeap.toArray(); + expect(heapArray).toBeInstanceOf(Array); + expect(heapArray.map(item => item.priority)).toEqual([2, 5, 9, 6]); + expect(minNumHeap.size).toBe(4); + }); + + it('should object Min Heap operations be proper', function () { + class MyObject { + keyA: string; + + constructor(keyA: string) { + this.keyA = keyA; + } + } + + const minObjHeap = new MinHeap(); + + const obj1 = new MyObject('a1'), obj6 = new MyObject('a6'), obj2 = new MyObject('a2'), + obj0 = new MyObject('a0'); + minObjHeap.add(obj1, 1); + expect(minObjHeap.has(obj1)).toBe(true); + expect(minObjHeap.has(obj6)).toBe(false); + minObjHeap.add(obj6, 6); + expect(minObjHeap.has(obj6)).toBe(true); + minObjHeap.add(obj2, 2); + expect(minObjHeap.has(obj2)).toBe(true); + minObjHeap.add(obj0, 0); + expect(minObjHeap.has(obj0)).toBe(true); + + const peek = minObjHeap.peek(); + peek && peek.val && expect(peek.val.keyA).toBe('a0'); + + const heapToArr = minObjHeap.toArray(); + expect(heapToArr.map(item => item.val?.keyA)).toEqual(['a0', 'a1', 'a2', 'a6']); + + const values = ['a0', 'a1', 'a2', 'a6']; + let i = 0; + while (minObjHeap.size > 0) { + const polled = minObjHeap.poll(); + expect(polled).toBeInstanceOf(HeapItem); + polled && expect(polled.val).toBeInstanceOf(MyObject); + polled && polled.val && expect(polled.val.keyA).toBe(values[i]); + i++; + } + }); +}); \ No newline at end of file diff --git a/tests/unit/data-structures/priority-queue/max-priority-queue.test.ts b/tests/unit/data-structures/priority-queue/max-priority-queue.test.ts new file mode 100644 index 0000000..a3367ad --- /dev/null +++ b/tests/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -0,0 +1,76 @@ +import {MaxPriorityQueue} from '../../../../src'; + +describe('MaxPriorityQueue Test1', () => { + + it('should add elements and maintain heap property', () => { + const priorityQueue = new MaxPriorityQueue(); + + priorityQueue.add(5); + priorityQueue.add(3); + priorityQueue.add(7); + priorityQueue.add(1); + + expect(priorityQueue.poll()).toBe(7); + expect(priorityQueue.poll()).toBe(5); + expect(priorityQueue.poll()).toBe(3); + expect(priorityQueue.poll()).toBe(1); + }); + + it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { + const priorityQueue = new MaxPriorityQueue<{ keyA: number }>({ + nodes: [{keyA: 5}, {keyA: 3}, {keyA: 1}], + comparator: (a, b) => b.keyA - a.keyA + }); + + priorityQueue.add({keyA: 7}); + + expect(priorityQueue.poll()?.keyA).toBe(7); + expect(priorityQueue.poll()?.keyA).toBe(5); + expect(priorityQueue.poll()?.keyA).toBe(3); + expect(priorityQueue.poll()?.keyA).toBe(1); + }); + + it('should return and remove the smallest element', () => { + const priorityQueue = new MaxPriorityQueue(); + priorityQueue.add(5); + priorityQueue.add(3); + priorityQueue.add(7); + + expect(priorityQueue.poll()).toBe(7); + expect(priorityQueue.poll()).toBe(5); + expect(priorityQueue.size).toBe(1); + }); + + it('should create a clone of the priority queue', () => { + const priorityQueue = new MaxPriorityQueue(); + priorityQueue.add(5); + priorityQueue.add(3); + priorityQueue.add(7); + + const clone = priorityQueue.clone(); + expect(clone.poll()).toBe(7); + expect(clone.poll()).toBe(5); + expect(clone.poll()).toBe(3); + expect(clone.isEmpty()).toBe(true); + }); + + it('should correctly heapify an array', () => { + const array = [5, 3, 7, 1]; + const heap = MaxPriorityQueue.heapify({nodes: array}); + + expect(heap.poll()).toBe(7); + expect(heap.poll()).toBe(5); + expect(heap.poll()).toBe(3); + expect(heap.poll()).toBe(1); + }); + + it('should correctly heapify an object array', () => { + const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; + const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>({nodes, comparator: (a, b) => b.keyA - a.keyA}); + + expect(maxPQ.poll()?.keyA).toBe(7); + expect(maxPQ.poll()?.keyA).toBe(5); + expect(maxPQ.poll()?.keyA).toBe(3); + expect(maxPQ.poll()?.keyA).toBe(1); + }); +}); \ No newline at end of file diff --git a/tests/unit/data-structures/priority-queue/min-priority-queue.test.ts b/tests/unit/data-structures/priority-queue/min-priority-queue.test.ts new file mode 100644 index 0000000..7dc0853 --- /dev/null +++ b/tests/unit/data-structures/priority-queue/min-priority-queue.test.ts @@ -0,0 +1,80 @@ +import {MinPriorityQueue} from '../../../../src'; + +describe('MinPriorityQueue Test1', () => { + + it('should check if a node exists in the queue', () => { + const priorityQueue = new MinPriorityQueue(); + priorityQueue.add(5); + + expect(priorityQueue.has(5)).toBe(true); + expect(priorityQueue.has(3)).toBe(false); + }); + + it('should return the smallest element without removing it', () => { + const priorityQueue = new MinPriorityQueue(); + priorityQueue.add(5); + priorityQueue.add(3); + priorityQueue.add(7); + + expect(priorityQueue.peek()).toBe(3); + expect(priorityQueue.size).toBe(3); + }); + + + it('should return the last element', () => { + const priorityQueue = new MinPriorityQueue(); + priorityQueue.add(5); + priorityQueue.add(3); + priorityQueue.add(7); + + expect(priorityQueue.leaf()).toBe(7); + }); + + it('should check if the queue is empty', () => { + const priorityQueue = new MinPriorityQueue(); + + expect(priorityQueue.isEmpty()).toBe(true); + + priorityQueue.add(5); + + expect(priorityQueue.isEmpty()).toBe(false); + }); + + it('should clear the queue', () => { + const priorityQueue = new MinPriorityQueue(); + priorityQueue.add(5); + priorityQueue.add(3); + priorityQueue.add(7); + + priorityQueue.clear(); + + expect(priorityQueue.size).toBe(0); + expect(priorityQueue.isEmpty()).toBe(true); + }); + + + it('should sort the elements', () => { + const priorityQueue = new MinPriorityQueue(); + priorityQueue.add(5); + priorityQueue.add(3); + priorityQueue.add(7); + priorityQueue.add(1); + + const sortedArray = priorityQueue.sort(); + expect(sortedArray).toEqual([1, 3, 5, 7]); + }); + +}); + + +describe('MinPriorityQueue Test2', () => { + it('should sorted.length to be the same as original data', () => { + // const sortCase3: number[] = Array.from(new Array(100), () => Math.floor(Math.random() * 2)); + // + // const minPriorityQueue = new MinPriorityQueue({nodes: sortCase3}); + // const nodeCount = minPriorityQueue.getNodes().length; + // const sorted = minPriorityQueue.sort(); + + // expect(sorted.length).toBe(nodeCount); // TODO Plan to support sorting of duplicate elements. + }); +}); \ No newline at end of file diff --git a/tests/unit/data-structures/priority-queue/priority-queue.test.ts b/tests/unit/data-structures/priority-queue/priority-queue.test.ts new file mode 100644 index 0000000..cb24f98 --- /dev/null +++ b/tests/unit/data-structures/priority-queue/priority-queue.test.ts @@ -0,0 +1,16 @@ +import {PriorityQueue} from '../../../../src'; + +describe('PriorityQueue Test1', () => { + + it('should validate a priority queue', () => { + const minPQ = new PriorityQueue({nodes: [1, 5, 7, 9, 3, 6, 2], comparator: (a, b) => a - b}); + + expect(minPQ.isValid()).toBe(true); + expect(PriorityQueue.isPriorityQueueified({nodes: minPQ.nodes, comparator: (a, b) => a - b})).toBe(true); + expect(PriorityQueue.isPriorityQueueified({nodes: minPQ.nodes, comparator: (a, b) => b - a})).toBe(false); + expect(PriorityQueue.isPriorityQueueified({ + nodes: [1, 5, 7, 9, 3, 6, 2], + comparator: (a, b) => b - a + })).toBe(false); + }); +}); \ No newline at end of file