bug fixed of method isValid for PriorityQueue and Heap, test cases enriched for PriorityQueue and Heap, SpecifyOptional type added

This commit is contained in:
Revone 2023-08-18 22:39:45 +08:00
parent 5db5561999
commit 694ca46893
17 changed files with 544 additions and 257 deletions

View file

@ -10,7 +10,13 @@ import type {HeapOptions} from '../types';
export class HeapItem<T = number> {
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<T = number> {
}
private _val: T | null;
get val(): T | null {
return this._val;
}
@ -27,11 +34,6 @@ export class HeapItem<T = number> {
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<T = number> {
@ -176,7 +178,7 @@ export abstract class Heap<T = number> {
* @param {T | HeapItem<T>} node - The parameter `node` can be of type `T` or `HeapItem<T>`.
* @returns a boolean value.
*/
has(node:T | HeapItem<T>): boolean {
has(node: T | HeapItem<T>): boolean {
if (node instanceof HeapItem<T>) {
return this.getPq().getNodes().includes(node);
} else {

View file

@ -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';

View file

@ -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<T = number> extends PriorityQueue<T> {
constructor(options?: Omit<PriorityQueueOptions<number>, 'comparator'>)
constructor(options: PriorityQueueOptions<T>)
/**
* 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<T>) {
constructor(options?: SpecifyOptional<PriorityQueueOptions<T>, '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<T extends number>(options?: Omit<PriorityQueueOptions<T>, 'comparator'>): MaxPriorityQueue<T>
static override heapify<T>(options: PriorityQueueOptions<T>): MaxPriorityQueue<T>
/**
* 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<T>(options: PriorityQueueOptions<T>): MaxPriorityQueue<T> {
const maxPQ = new MaxPriorityQueue<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;
}
});
maxPQ._fix();
return maxPQ;
}
}

View file

@ -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<T = number> extends PriorityQueue<T> {
constructor(options?: Omit<PriorityQueueOptions<number>, 'comparator'>)
constructor(options: PriorityQueueOptions<T>)
/**
* 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<T>) {
constructor(options?: SpecifyOptional<PriorityQueueOptions<T>, '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<T extends number>(options?: Omit<PriorityQueueOptions<T>, 'comparator'>): MinPriorityQueue<T>
static override heapify<T>(options: PriorityQueueOptions<T>): MinPriorityQueue<T>
/**
* 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<T>(options: PriorityQueueOptions<T>): MinPriorityQueue<T> {
const minPQ = new MinPriorityQueue<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;
}
});
minPQ._fix();
return minPQ;
}
}

View file

@ -8,6 +8,22 @@
import type {PriorityQueueComparator, PriorityQueueDFSOrderPattern, PriorityQueueOptions} from '../types';
export class PriorityQueue<T = number> {
/**
* 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<T>) {
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<T = number> {
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<T>) {
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<T>(options: PriorityQueueOptions<T>) {
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<T>(options: Omit<PriorityQueueOptions<T>, '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<T = number> {
return new PriorityQueue<T>({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<T> = (a: T, b: T) => {
const aKey = a as unknown as number, bKey = b as unknown as number;
@ -255,105 +350,5 @@ export class PriorityQueue<T = number> {
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<T>(options: PriorityQueueOptions<T>) {
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<T>(options: Omit<PriorityQueueOptions<T>, 'isFix'>) {
return new PriorityQueue({...options, isFix: true}).isValid();
}
// --- end additional methods ---
}

View file

@ -0,0 +1 @@
export * from './tree';

View file

@ -0,0 +1,54 @@
export class TreeNode<T = number> {
id: string;
name?: string | undefined;
value?: T | undefined;
children?: TreeNode<T>[] | undefined;
constructor(id: string, name?: string, value?: T, children?: TreeNode<T>[]) {
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<T> | TreeNode<T> []) {
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<T>, 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;
}
}

View file

@ -1,4 +1,6 @@
export type ToThunkFn = () => ReturnType<TrlFn>;
export type Thunk = () => ReturnType<ToThunkFn> & { __THUNK__: Symbol };
export type TrlFn = (...args: any[]) => any;
export type TrlAsyncFn = (...args: any[]) => any;
export type TrlAsyncFn = (...args: any[]) => any;
export type SpecifyOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

View file

@ -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;
}
}

View file

@ -1,5 +1,3 @@
import {DirectedEdge, DirectedGraph, DirectedVertex} from '../../../../src';
describe('UndirectedGraph Test1', () => {
});

View file

@ -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<number>();
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<number>)
poll1 instanceof HeapItem && expect(poll1.val).toBe(0);
const poll2 = minNumHeap.poll();
expect(poll2).toBeInstanceOf(HeapItem<number>)
poll2 instanceof HeapItem && expect(poll2.val).toBe(1);
const peek1 = minNumHeap.peek();
expect(peek1).toBeInstanceOf(HeapItem<number>)
peek1 instanceof HeapItem && expect(peek1.val).toBe(2);
const heapArray = minNumHeap.toArray();
expect(heapArray).toBeInstanceOf(Array<HeapItem>);
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<MyObject>();
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<MyObject>);
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);
});
});

View file

@ -1 +0,0 @@
export * from './heap.test';

View file

@ -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++;
}
});
});

View file

@ -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<number>();
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<number>)
poll1 instanceof HeapItem && expect(poll1.val).toBe(0);
const poll2 = minNumHeap.poll();
expect(poll2).toBeInstanceOf(HeapItem<number>)
poll2 instanceof HeapItem && expect(poll2.val).toBe(1);
const peek1 = minNumHeap.peek();
expect(peek1).toBeInstanceOf(HeapItem<number>)
peek1 instanceof HeapItem && expect(peek1.val).toBe(2);
const heapArray = minNumHeap.toArray();
expect(heapArray).toBeInstanceOf(Array<HeapItem>);
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<MyObject>();
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<MyObject>);
polled && expect(polled.val).toBeInstanceOf(MyObject);
polled && polled.val && expect(polled.val.keyA).toBe(values[i]);
i++;
}
});
});

View file

@ -0,0 +1,76 @@
import {MaxPriorityQueue} from '../../../../src';
describe('MaxPriorityQueue Test1', () => {
it('should add elements and maintain heap property', () => {
const priorityQueue = new MaxPriorityQueue<number>();
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<number>();
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<number>();
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<number>({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);
});
});

View file

@ -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<number>();
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<number>();
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<number>();
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<number>();
expect(priorityQueue.isEmpty()).toBe(true);
priorityQueue.add(5);
expect(priorityQueue.isEmpty()).toBe(false);
});
it('should clear the queue', () => {
const priorityQueue = new MinPriorityQueue<number>();
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<number>();
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<number>(100), () => Math.floor(Math.random() * 2));
//
// const minPriorityQueue = new MinPriorityQueue<number>({nodes: sortCase3});
// const nodeCount = minPriorityQueue.getNodes().length;
// const sorted = minPriorityQueue.sort();
// expect(sorted.length).toBe(nodeCount); // TODO Plan to support sorting of duplicate elements.
});
});

View file

@ -0,0 +1,16 @@
import {PriorityQueue} from '../../../../src';
describe('PriorityQueue Test1', () => {
it('should validate a priority queue', () => {
const minPQ = new PriorityQueue<number>({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);
});
});