[test] Increase the test coverage to 89.51.

This commit is contained in:
Revone 2023-10-28 23:54:27 +08:00
parent 6c45f53f72
commit bd1720973a
52 changed files with 2248 additions and 448 deletions

View file

@ -1,6 +1,6 @@
{
"name": "data-structure-typed",
"version": "1.39.0",
"version": "1.39.1",
"description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",
"main": "dist/cjs/index.js",
"module": "dist/mjs/index.js",

View file

@ -7,7 +7,7 @@
*/
import {BST, BSTNode} from './bst';
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types';
import {MapCallback} from '../../types';
import {OneParamCallback} from '../../types';
import {IBinaryTree} from '../../interfaces';
export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNested<V>> extends BSTNode<V, N> {
@ -21,7 +21,8 @@ export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNeste
export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTreeNodeNested<V>>>
extends BST<V, N>
implements IBinaryTree<V, N> {
implements IBinaryTree<V, N>
{
/**
* This is a constructor function for an AVL tree data structure in TypeScript.
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the
@ -73,7 +74,7 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
* `this._defaultCallbackByKey`
* @returns The method is returning an array of `BinaryTreeDeletedResult<N>` objects.
*/
override delete<C extends MapCallback<N>>(
override delete<C extends OneParamCallback<N>>(
identifier: ReturnType<C>,
callback: C = this._defaultCallbackByKey as C
): BinaryTreeDeletedResult<N>[] {
@ -160,7 +161,7 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
// Balance Restoration: If a balance issue is discovered after inserting a node, it requires balance restoration operations. Balance restoration includes four basic cases where rotation operations need to be performed to fix the balance:
switch (
this._balanceFactor(A) // second O(1)
) {
) {
case -2:
if (A && A.left) {
if (this._balanceFactor(A.left) <= 0) {

View file

@ -17,7 +17,7 @@ export class BinaryIndexedTree {
* @param - - `frequency`: The default frequency value. It is optional and has a default
* value of 0.
*/
constructor({frequency = 0, max}: { frequency?: number; max: number }) {
constructor({frequency = 0, max}: {frequency?: number; max: number}) {
this._freq = frequency;
this._max = max;
this._freqMap = {0: 0};

View file

@ -6,16 +6,8 @@
* @license MIT License
*/
import type {
BFSCallback,
BFSCallbackReturn,
BinaryTreeNodeKey,
BinaryTreeNodeNested,
BinaryTreeOptions,
MapCallback,
MapCallbackReturn
} from '../../types';
import {BinaryTreeDeletedResult, DefaultMapCallback, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
import type {OneParamCallback, BinaryTreeNodeKey, BinaryTreeNodeNested, BinaryTreeOptions} from '../../types';
import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
import {IBinaryTree} from '../../interfaces';
import {trampoline} from '../../utils';
import {Queue} from '../queue';
@ -116,7 +108,8 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
* @template N - The type of the binary tree's nodes.
*/
export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>>
implements IBinaryTree<V, N> {
implements IBinaryTree<V, N>
{
/**
* Creates a new instance of BinaryTree.
* @param {BinaryTreeOptions} [options] - The options for the binary tree.
@ -285,10 +278,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return keysOrNodes.length === this.addMany(keysOrNodes, data).length;
}
delete<C extends MapCallback<N>>(identifier: ReturnType<C> | N): BinaryTreeDeletedResult<N>[];
delete<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C): BinaryTreeDeletedResult<N>[];
/**
* The `delete` function removes a node from a binary search tree and returns the deleted node along
* with the parent node that needs to be balanced.
@ -303,13 +292,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* included in the result. The `callback` parameter has a default value of
* `this._defaultCallbackByKey`, which
*/
delete<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
delete<C extends OneParamCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = this._defaultCallbackByKey as C
): BinaryTreeDeletedResult<N>[] {
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
if (!this.root) return bstDeletedResult;
if (identifier instanceof BinaryTreeNode) callback = (node => node) as C;
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
const curr = this.get(identifier, callback);
if (!curr) return bstDeletedResult;
@ -320,7 +309,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (!curr.left) {
if (!parent) {
if (curr.right !== undefined) this._setRoot(curr.right);
// Handle the case when there's only one root node
this._setRoot(null);
} else {
const {familyPosition: fp} = curr;
if (fp === FamilyPosition.LEFT || fp === FamilyPosition.ROOT_LEFT) {
@ -405,7 +395,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return -1;
}
const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}];
const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}];
let maxHeight = 0;
while (stack.length > 0) {
@ -489,29 +479,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
}
getNodes<C extends MapCallback<N>>(identifier: ReturnType<C> | N): N[];
getNodes<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C): N[];
getNodes<C extends MapCallback<N>>(identifier: ReturnType<C> | N, onlyOne: boolean): N[];
getNodes<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C, onlyOne: boolean): N[];
getNodes<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
callback: C,
onlyOne: boolean,
beginRoot: N | null
): N[];
getNodes<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
callback: C,
onlyOne: boolean,
beginRoot: N | null,
iterationType: IterationType
): N[];
/**
* The function `getNodes` returns an array of nodes that match a given node property, using either
* recursive or iterative traversal.
@ -533,15 +500,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* traverse the binary tree. It can have two possible values:
* @returns The function `getNodes` returns an array of nodes (`N[]`).
*/
getNodes<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
getNodes<C extends OneParamCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = this._defaultCallbackByKey as C,
onlyOne = false,
beginRoot: N | null = this.root,
iterationType = this.iterationType
): N[] {
if (!beginRoot) return [];
if (identifier instanceof BinaryTreeNode) callback = (node => node) as C;
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
const ans: N[] = [];
if (iterationType === IterationType.RECURSIVE) {
@ -574,14 +541,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
has<C extends MapCallback<N>>(identifier: ReturnType<C> | N): boolean;
has<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C): boolean;
has<C extends MapCallback<N>>(identifier: ReturnType<C> | N, beginRoot: N | null): boolean;
has<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C, beginRoot: N | null): boolean;
/**
* The function checks if a binary tree has a node with a given property or key.
* @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of
@ -599,32 +558,17 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* performed when searching for nodes in the binary tree. It can have one of the following values:
* @returns a boolean value.
*/
has<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
has<C extends OneParamCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = this._defaultCallbackByKey as C,
beginRoot = this.root,
iterationType = this.iterationType
): boolean {
if (identifier instanceof BinaryTreeNode) callback = (node => node) as C;
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
// TODO may support finding node by value equal
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
}
get<C extends MapCallback<N>>(identifier: ReturnType<C> | N): N | null;
get<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C): N | null;
get<C extends MapCallback<N>>(identifier: ReturnType<C> | N, beginRoot: N | null): N | null;
get<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C, beginRoot: N | null): N | null;
get<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
callback: C,
beginRoot: N | null,
iterationType: IterationType
): N | null;
/**
* The function `get` returns the first node in a binary tree that matches the given property or key.
* @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of
@ -640,13 +584,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* performed when searching for a node in the binary tree. It can have one of the following values:
* @returns either the found node (of type N) or null if no node is found.
*/
get<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
get<C extends OneParamCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = this._defaultCallbackByKey as C,
beginRoot = this.root,
iterationType = this.iterationType
): N | null {
if (identifier instanceof BinaryTreeNode) callback = (node => node) as C;
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
// TODO may support finding node by value equal
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
}
@ -750,7 +694,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* possible values:
* @returns The function `isSubtreeBST` returns a boolean value.
*/
isSubtreeBST(beginRoot: N, iterationType = this.iterationType): boolean {
isSubtreeBST(beginRoot: N | null, iterationType = this.iterationType): boolean {
// TODO there is a bug
if (!beginRoot) return true;
@ -805,16 +749,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* start from the root of the tree.
* @param iterationType - The `iterationType` parameter determines the type of traversal to be
* performed on the binary tree. It can have two possible values:
* @returns The function `subTreeTraverse` returns an array of `MapCallbackReturn<N>`.
* @returns The function `subTreeTraverse` returns an array of `ReturnType<OneParamCallback<N>>`.
*/
subTreeTraverse<C extends MapCallback<N>>(
subTreeTraverse<C extends OneParamCallback<N>>(
callback: C = this._defaultCallbackByKey as C,
beginRoot: BinaryTreeNodeKey | N | null = this.root,
iterationType = this.iterationType
): ReturnType<C>[] {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
const ans: MapCallbackReturn<N>[] = [];
const ans: ReturnType<OneParamCallback<N>>[] = [];
if (!beginRoot) return ans;
if (iterationType === IterationType.RECURSIVE) {
@ -852,16 +796,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* is `null`, an empty array will be returned.
* @param {IterationType} iterationType - The `iterationType` parameter determines the type of
* iteration used in the depth-first search algorithm. It can have two possible values:
* @returns The function `dfs` returns an array of `MapCallbackReturn<N>` values.
* @returns The function `dfs` returns an array of `ReturnType<OneParamCallback<N>>` values.
*/
dfs<C extends MapCallback<N>>(
dfs<C extends OneParamCallback<N>>(
callback: C = this._defaultCallbackByKey as C,
pattern: DFSOrderPattern = 'in',
beginRoot: N | null = this.root,
iterationType: IterationType = IterationType.ITERATIVE
): ReturnType<C>[] {
if (!beginRoot) return [];
const ans: MapCallbackReturn<N>[] = [];
const ans: ReturnType<OneParamCallback<N>>[] = [];
if (iterationType === IterationType.RECURSIVE) {
const _traverse = (node: N) => {
switch (pattern) {
@ -888,7 +832,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
_traverse(beginRoot);
} else {
// 0: visit, 1: print
const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}];
const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}];
while (stack.length > 0) {
const cur = stack.pop();
@ -930,22 +874,22 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* function on each node.
* @param callback - The `callback` parameter is a function that will be called for each node in the
* breadth-first search. It takes a node of type `N` as its argument and returns a value of type
* `BFSCallbackReturn<N>`. The default value for this parameter is `this._defaultCallbackByKey
* `ReturnType<OneParamCallback<N>>`. The default value for this parameter is `this._defaultCallbackByKey
* @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first
* search. It determines from which node the search will begin. If `beginRoot` is `null`, the search
* will not be performed and an empty array will be returned.
* @param iterationType - The `iterationType` parameter determines the type of iteration to be used
* in the breadth-first search (BFS) algorithm. It can have two possible values:
* @returns The function `bfs` returns an array of `BFSCallbackReturn<N>[]`.
* @returns The function `bfs` returns an array of `ReturnType<OneParamCallback<N>>[]`.
*/
bfs<C extends BFSCallback<N> = BFSCallback<N, BinaryTreeNodeKey>>(
bfs<C extends OneParamCallback<N>>(
callback: C = this._defaultCallbackByKey as C,
beginRoot: N | null = this.root,
iterationType = this.iterationType
): ReturnType<C>[] {
if (!beginRoot) return [];
const ans: BFSCallbackReturn<N>[] = [];
const ans: ReturnType<OneParamCallback<N>>[] = [];
if (iterationType === IterationType.RECURSIVE) {
const queue = new Queue<N>([beginRoot]);
@ -995,7 +939,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* level in a binary tree. Each inner array contains the return type of the provided callback
* function `C` applied to the nodes at that level.
*/
listLevels<C extends BFSCallback<N> = BFSCallback<N, BinaryTreeNodeKey>>(
listLevels<C extends OneParamCallback<N>>(
callback: C = this._defaultCallbackByKey as C,
beginRoot: N | null = this.root,
iterationType = this.iterationType
@ -1054,7 +998,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* The `morris` function performs a depth-first traversal of a binary tree using the Morris traversal
* algorithm and returns an array of values obtained by applying a callback function to each node.
* @param callback - The `callback` parameter is a function that will be called on each node in the
* tree. It takes a node of type `N` as input and returns a value of type `MapCallbackReturn<N>`. The
* tree. It takes a node of type `N` as input and returns a value of type `ReturnType<OneParamCallback<N>>`. The
* default value for this parameter is `this._defaultCallbackByKey`.
* @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function
* determines the order in which the nodes of a binary tree are traversed. It can have one of the
@ -1062,15 +1006,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the Morris
* traversal. It specifies the root node of the tree from which the traversal should begin. If
* `beginRoot` is `null`, an empty array will be returned.
* @returns The `morris` function returns an array of `MapCallbackReturn<N>` values.
* @returns The `morris` function returns an array of `ReturnType<OneParamCallback<N>>` values.
*/
morris<C extends MapCallback<N>>(
morris<C extends OneParamCallback<N>>(
callback: C = this._defaultCallbackByKey as C,
pattern: DFSOrderPattern = 'in',
beginRoot: N | null = this.root
): ReturnType<C>[] {
if (beginRoot === null) return [];
const ans: MapCallbackReturn<N>[] = [];
const ans: ReturnType<OneParamCallback<N>>[] = [];
let cur: N | null | undefined = beginRoot;
const _reverseEdge = (node: N | null | undefined) => {
@ -1177,7 +1121,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* the tree's structure should be restored to its original state to maintain the tree's integrity.
* This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape.
*/
protected _defaultCallbackByKey: DefaultMapCallback<N> = node => node.key;
protected _defaultCallbackByKey: OneParamCallback<N, BinaryTreeNodeKey> = node => node.key;
/**
* The function `_addTo` adds a new node to a binary tree if there is an available position.

View file

@ -5,14 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {
BinaryTreeNodeKey,
BSTComparator,
BSTNodeNested,
BSTOptions,
MapCallback,
MapCallbackReturn
} from '../../types';
import type {BinaryTreeNodeKey, BSTComparator, BSTNodeNested, BSTOptions, OneParamCallback} from '../../types';
import {CP, IterationType} from '../../types';
import {BinaryTree, BinaryTreeNode} from './binary-tree';
import {IBinaryTree} from '../../interfaces';
@ -26,7 +19,8 @@ export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extend
export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>>
extends BinaryTree<V, N>
implements IBinaryTree<V, N> {
implements IBinaryTree<V, N>
{
/**
* The constructor function initializes a binary search tree object with an optional comparator
* function.
@ -227,7 +221,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* callback.
* @param {ReturnType<C> | N} identifier - The `nodeProperty` parameter is used to specify the
* property of the binary tree node that you want to search for. It can be either a specific key
* value (`BinaryTreeNodeKey`) or a custom callback function (`MapCallback<N>`) that determines
* value (`BinaryTreeNodeKey`) or a custom callback function (`OneParamCallback<N>`) that determines
* whether a node matches the desired property.
* @param callback - The `callback` parameter is a function that is used to determine whether a node
* matches the desired property. It takes a node as input and returns a boolean value indicating
@ -240,8 +234,8 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* @returns either the first node that matches the given nodeProperty and callback, or null if no
* matching node is found.
*/
override get<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
override get<C extends OneParamCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = this._defaultCallbackByKey as C,
beginRoot = this.root,
iterationType = this.iterationType
@ -291,8 +285,8 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* traverse the binary tree. It can have one of the following values:
* @returns an array of nodes (N[]).
*/
override getNodes<C extends MapCallback<N>>(
identifier: ReturnType<C> | N,
override getNodes<C extends OneParamCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = this._defaultCallbackByKey as C,
onlyOne = false,
beginRoot: N | null = this.root,
@ -363,16 +357,16 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* (`BinaryTreeNodeKey`), or `null` to
* @param iterationType - The `iterationType` parameter determines whether the traversal should be
* done recursively or iteratively. It can have two possible values:
* @returns The function `lesserOrGreaterTraverse` returns an array of `MapCallbackReturn<N>`.
* @returns The function `lesserOrGreaterTraverse` returns an array of `ReturnType<OneParamCallback<N>>`.
*/
lesserOrGreaterTraverse<C extends MapCallback<N>>(
lesserOrGreaterTraverse<C extends OneParamCallback<N>>(
callback: C = this._defaultCallbackByKey as C,
lesserOrGreater: CP = CP.lt,
targetNode: BinaryTreeNodeKey | N | null = this.root,
iterationType = this.iterationType
): ReturnType<C>[] {
if (typeof targetNode === 'number') targetNode = this.get(targetNode);
const ans: MapCallbackReturn<N>[] = [];
const ans: ReturnType<OneParamCallback<N>>[] = [];
if (!targetNode) return ans;
const targetKey = targetNode.key;
if (!this.root) return ans;

View file

@ -21,7 +21,8 @@ export class RBTreeNode<V = any, N extends RBTreeNode<V, N> = RBTreeNodeNested<V
export class RBTree<V, N extends RBTreeNode<V, N> = RBTreeNode<V, RBTreeNodeNested<V>>>
extends BST<V, N>
implements IBinaryTree<V, N> {
implements IBinaryTree<V, N>
{
constructor(options?: RBTreeOptions) {
super(options);
}

View file

@ -6,7 +6,7 @@
* @license MIT License
*/
import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types';
import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, MapCallback} from '../../types';
import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, OneParamCallback} from '../../types';
import {IBinaryTree} from '../../interfaces';
import {AVLTree, AVLTreeNode} from './avl-tree';
@ -37,7 +37,8 @@ export class TreeMultisetNode<
*/
export class TreeMultiset<V = any, N extends TreeMultisetNode<V, N> = TreeMultisetNode<V, TreeMultisetNodeNested<V>>>
extends AVLTree<V, N>
implements IBinaryTree<V, N> {
implements IBinaryTree<V, N>
{
/**
* The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to
* merge duplicated values.
@ -274,7 +275,7 @@ export class TreeMultiset<V = any, N extends TreeMultisetNode<V, N> = TreeMultis
* decremented by 1 and
* @returns The method `delete` returns an array of `BinaryTreeDeletedResult<N>` objects.
*/
override delete<C extends MapCallback<N>>(
override delete<C extends OneParamCallback<N>>(
identifier: ReturnType<C>,
callback: C = this._defaultCallbackByKey as C,
ignoreCount = false

View file

@ -105,7 +105,8 @@ export abstract class AbstractEdge<V = any> {
export abstract class AbstractGraph<
V extends AbstractVertex<any> = AbstractVertex<any>,
E extends AbstractEdge<any> = AbstractEdge<any>
> implements IGraph<V, E> {
> implements IGraph<V, E>
{
private _vertices: Map<VertexKey, V> = new Map<VertexKey, V>();
get vertices(): Map<VertexKey, V> {
@ -196,7 +197,7 @@ export abstract class AbstractGraph<
* @returns a boolean value. It returns true if at least one vertex was successfully removed, and false if no vertices
* were removed.
*/
removeAllVertices(vertices: V[] | VertexKey[]): boolean {
removeManyVertices(vertices: V[] | VertexKey[]): boolean {
const removed: boolean[] = [];
for (const v of vertices) {
removed.push(this.deleteVertex(v));
@ -553,14 +554,14 @@ export abstract class AbstractGraph<
}
getMinDist &&
distMap.forEach((d, v) => {
if (v !== srcVertex) {
if (d < minDist) {
minDist = d;
if (genPaths) minDest = v;
distMap.forEach((d, v) => {
if (v !== srcVertex) {
if (d < minDist) {
minDist = d;
if (genPaths) minDest = v;
}
}
}
});
});
genPaths && getPaths(minDest);
@ -622,7 +623,7 @@ export abstract class AbstractGraph<
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
}
const heap = new PriorityQueue<{ key: number; val: V }>({comparator: (a, b) => a.key - b.key});
const heap = new PriorityQueue<{key: number; val: V}>({comparator: (a, b) => a.key - b.key});
heap.add({key: 0, val: srcVertex});
distMap.set(srcVertex, 0);
@ -851,7 +852,7 @@ export abstract class AbstractGraph<
* `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest
* path between vertices in the
*/
floyd(): { costs: number[][]; predecessor: (V | null)[][] } {
floyd(): {costs: number[][]; predecessor: (V | null)[][]} {
const idAndVertices = [...this._vertices];
const n = idAndVertices.length;

View file

@ -64,7 +64,8 @@ export class DirectedEdge<V = any> extends AbstractEdge<V> {
export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E extends DirectedEdge<any> = DirectedEdge>
extends AbstractGraph<V, E>
implements IGraph<V, E> {
implements IGraph<V, E>
{
/**
* The constructor function initializes an instance of a class.
*/

View file

@ -109,9 +109,9 @@ export class MapGraph<V extends MapVertex<V['val']> = MapVertex, E extends MapEd
*/
override createVertex(
key: VertexKey,
val?: V['val'],
lat: number = this.origin[0],
long: number = this.origin[1]
long: number = this.origin[1],
val?: V['val']
): V {
return new MapVertex(key, lat, long, val) as V;
}

View file

@ -51,11 +51,12 @@ export class UndirectedEdge<V = number> extends AbstractEdge<V> {
}
export class UndirectedGraph<
V extends UndirectedVertex<any> = UndirectedVertex,
E extends UndirectedEdge<any> = UndirectedEdge
>
V extends UndirectedVertex<any> = UndirectedVertex,
E extends UndirectedEdge<any> = UndirectedEdge
>
extends AbstractGraph<V, E>
implements IGraph<V, E> {
implements IGraph<V, E>
{
/**
* The constructor initializes a new Map object to store edges.
*/

View file

@ -157,7 +157,7 @@ export class HashMap<K, V> {
}
}
* entries(): IterableIterator<[K, V]> {
*entries(): IterableIterator<[K, V]> {
for (const bucket of this.table) {
if (bucket) {
for (const [key, value] of bucket) {

View file

@ -1,2 +1 @@
export class TreeMap {
}
export class TreeMap {}

View file

@ -1,2 +1 @@
export class TreeSet {
}
export class TreeSet {}

View file

@ -11,7 +11,7 @@ export class Heap<E = any> {
protected nodes: E[] = [];
protected readonly comparator: Comparator<E>;
constructor(options: { comparator: Comparator<E>; nodes?: E[] }) {
constructor(options: {comparator: Comparator<E>; nodes?: E[]}) {
this.comparator = options.comparator;
if (options.nodes && options.nodes.length > 0) {
this.nodes = options.nodes;
@ -39,7 +39,7 @@ export class Heap<E = any> {
* @returns A new Heap instance.
* @param options
*/
static heapify<E>(options: { nodes: E[]; comparator: Comparator<E> }): Heap<E> {
static heapify<E>(options: {nodes: E[]; comparator: Comparator<E>}): Heap<E> {
return new Heap<E>(options);
}

View file

@ -11,7 +11,7 @@ import type {Comparator} from '../../types';
export class MaxHeap<E = any> extends Heap<E> {
constructor(
options: { comparator: Comparator<E>; nodes?: E[] } = {
options: {comparator: Comparator<E>; nodes?: E[]} = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');

View file

@ -11,7 +11,7 @@ import type {Comparator} from '../../types';
export class MinHeap<E = any> extends Heap<E> {
constructor(
options: { comparator: Comparator<E>; nodes?: E[] } = {
options: {comparator: Comparator<E>; nodes?: E[]} = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');

View file

@ -485,7 +485,7 @@ export class SinglyLinkedList<E = any> {
return count;
}
* [Symbol.iterator]() {
*[Symbol.iterator]() {
let current = this.head;
while (current) {

View file

@ -14,7 +14,7 @@ export class MatrixNTI2D<V = any> {
* given initial value or 0 if not provided.
* @param options - An object containing the following properties:
*/
constructor(options: { row: number; col: number; initialVal?: V }) {
constructor(options: {row: number; col: number; initialVal?: V}) {
const {row, col, initialVal} = options;
this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0));
}

View file

@ -5,7 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import Vector2D from './vector2d';
import {Vector2D} from './vector2d';
export class Matrix2D {
private readonly _matrix: number[][];
@ -209,5 +209,3 @@ export class Matrix2D {
return new Vector2D(this._matrix[0][0], this._matrix[1][0]);
}
}
export default Matrix2D;

View file

@ -10,8 +10,7 @@ export class Vector2D {
public x: number = 0,
public y: number = 0,
public w: number = 1 // needed for matrix multiplication
) {
}
) {}
/**
* The function checks if the x and y values of a point are both zero.
@ -313,5 +312,3 @@ export class Vector2D {
this.y = 0;
}
}
export default Vector2D;

View file

@ -10,7 +10,7 @@ import type {Comparator} from '../../types';
export class MaxPriorityQueue<E = any> extends PriorityQueue<E> {
constructor(
options: { comparator: Comparator<E>; nodes?: E[] } = {
options: {comparator: Comparator<E>; nodes?: E[]} = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');

View file

@ -10,7 +10,7 @@ import type {Comparator} from '../../types';
export class MinPriorityQueue<E = any> extends PriorityQueue<E> {
constructor(
options: { comparator: Comparator<E>; nodes?: E[] } = {
options: {comparator: Comparator<E>; nodes?: E[]} = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
throw new Error('The a, b params of compare function must be number');

View file

@ -10,7 +10,7 @@ import {Heap} from '../heap';
import {Comparator} from '../../types';
export class PriorityQueue<E = any> extends Heap<E> {
constructor(options: { comparator: Comparator<E>; nodes?: E[] }) {
constructor(options: {comparator: Comparator<E>; nodes?: E[]}) {
super(options);
}
}

View file

@ -9,8 +9,7 @@ import {DoublyLinkedList} from '../linked-list';
// O(n) time complexity of obtaining the value
// O(1) time complexity of adding at the beginning and the end
export class Deque<E = any> extends DoublyLinkedList<E> {
}
export class Deque<E = any> extends DoublyLinkedList<E> {}
// O(1) time complexity of obtaining the value
// O(n) time complexity of adding at the beginning and the end
@ -20,9 +19,9 @@ export class ObjectDeque<E = number> {
if (capacity !== undefined) this._capacity = capacity;
}
private _nodes: { [key: number]: E } = {};
private _nodes: {[key: number]: E} = {};
get nodes(): { [p: number]: E } {
get nodes(): {[p: number]: E} {
return this._nodes;
}
@ -157,7 +156,7 @@ export class ObjectDeque<E = number> {
return this._size <= 0;
}
protected _seNodes(value: { [p: number]: E }) {
protected _seNodes(value: {[p: number]: E}) {
this._nodes = value;
}

View file

@ -183,7 +183,7 @@ export class Queue<E = any> {
return new Queue(this.nodes.slice(this.offset));
}
* [Symbol.iterator]() {
*[Symbol.iterator]() {
for (const item of this.nodes) {
yield item;
}

View file

@ -1,10 +1,10 @@
import {BinaryTreeNode} from '../data-structures';
import {BinaryTreeDeletedResult, BinaryTreeNodeKey, BinaryTreeNodeNested, MapCallback} from '../types';
import {BinaryTreeDeletedResult, BinaryTreeNodeKey, BinaryTreeNodeNested, OneParamCallback} from '../types';
export interface IBinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNodeNested<V>> {
createNode(key: BinaryTreeNodeKey, val?: N['val']): N;
add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined;
delete<C extends MapCallback<N>>(identifier: ReturnType<C> | N, callback: C): BinaryTreeDeletedResult<N>[];
delete<C extends OneParamCallback<N>>(identifier: ReturnType<C> | null, callback: C): BinaryTreeDeletedResult<N>[];
}

View file

@ -24,10 +24,6 @@ export enum FamilyPosition {
export type BinaryTreeNodeKey = number;
export type BFSCallback<N, D = any> = (node: N, level?: number) => D;
export type BFSCallbackReturn<N> = ReturnType<BFSCallback<N>>;
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined; needBalanced: N | null };
export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

View file

@ -1,6 +1,6 @@
export type Direction = 'up' | 'right' | 'down' | 'left';
export type Turning = { [key in Direction]: Direction };
export type Turning = {[key in Direction]: Direction};
export type NavigatorParams<T = any> = {
matrix: T[][];

View file

@ -1,14 +1,8 @@
import {BinaryTreeNodeKey} from './data-structures';
export type Comparator<T> = (a: T, b: T) => number;
export type DFSOrderPattern = 'pre' | 'in' | 'post';
export type MapCallback<N, D = any> = (node: N) => D;
export type DefaultMapCallback<N, D = BinaryTreeNodeKey> = (node: N) => D;
export type MapCallbackReturn<N> = ReturnType<MapCallback<N>>;
export type OneParamCallback<N, D = any> = (node: N) => D;
export enum CP {
lt = 'lt',

View file

@ -1,5 +1,5 @@
export type ToThunkFn = () => ReturnType<TrlFn>;
export type Thunk = () => ReturnType<ToThunkFn> & { __THUNK__: symbol };
export type Thunk = () => ReturnType<ToThunkFn> & {__THUNK__: symbol};
export type TrlFn = (...args: any[]) => any;
export type TrlAsyncFn = (...args: any[]) => any;

View file

@ -1,6 +1,6 @@
export type KeyValueObject = { [key: string]: any };
export type KeyValueObject = {[key: string]: any};
export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol };
export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol};
export type NonNumberNonObjectButDefined = string | boolean | symbol | null;

View file

@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => {
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objBST = new BST<{ key: number; keyA: number }>();
const objBST = new BST<{key: number; keyA: number}>();
expect(objBST).toBeInstanceOf(BST);
objBST.add(11, {key: 11, keyA: 11});
objBST.add(3, {key: 3, keyA: 3});

View file

@ -1,4 +1,4 @@
import {AVLTree, AVLTreeNode, CP} from '../../../../src';
import {AVLTree, AVLTreeNode, CP, IterationType} from '../../../../src';
describe('AVL Tree Test', () => {
it('should perform various operations on a AVL Tree', () => {
@ -109,8 +109,117 @@ describe('AVL Tree Test', () => {
});
});
describe('AVL Tree Test recursively', () => {
it('should perform various operations on a AVL Tree', () => {
const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
const tree = new AVLTree<number>({iterationType: IterationType.RECURSIVE});
for (const i of arr) tree.add(i, i);
const node6 = tree.get(6);
expect(node6 && tree.getHeight(node6)).toBe(3);
expect(node6 && tree.getDepth(node6)).toBe(1);
const getNodeById = tree.get(10);
expect(getNodeById?.key).toBe(10);
const getMinNodeByRoot = tree.getLeftMost();
expect(getMinNodeByRoot?.key).toBe(1);
const node15 = tree.get(15);
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15);
expect(getMinNodeBySpecificNode?.key).toBe(12);
let subTreeSum = 0;
node15 && tree.subTreeTraverse(node => (subTreeSum += node.key), node15);
expect(subTreeSum).toBe(70);
let lesserSum = 0;
tree.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
// node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class.
expect(node15?.val).toBe(15);
const dfs = tree.dfs(node => node, 'in');
expect(dfs[0].key).toBe(1);
expect(dfs[dfs.length - 1].key).toBe(16);
tree.perfectlyBalance();
const bfs = tree.bfs(node => node);
expect(tree.isPerfectlyBalanced()).toBe(true);
expect(bfs[0].key).toBe(8);
expect(bfs[bfs.length - 1].key).toBe(16);
expect(tree.delete(11)[0].deleted?.key).toBe(11);
expect(tree.isAVLBalanced()).toBe(true);
expect(node15 && tree.getHeight(node15)).toBe(2);
expect(tree.delete(1)[0].deleted?.key).toBe(1);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(4);
expect(tree.delete(4)[0].deleted?.key).toBe(4);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(4);
expect(tree.delete(10)[0].deleted?.key).toBe(10);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.delete(15)[0].deleted?.key).toBe(15);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.delete(5)[0].deleted?.key).toBe(5);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.delete(13)[0].deleted?.key).toBe(13);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.delete(3)[0].deleted?.key).toBe(3);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.delete(8)[0].deleted?.key).toBe(8);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(tree.delete(6)[0].deleted?.key).toBe(6);
expect(tree.delete(6).length).toBe(0);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(2);
expect(tree.delete(7)[0].deleted?.key).toBe(7);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(2);
expect(tree.delete(9)[0].deleted?.key).toBe(9);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(2);
expect(tree.delete(14)[0].deleted?.key).toBe(14);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(1);
expect(tree.isAVLBalanced()).toBe(true);
const lastBFSIds = tree.bfs();
expect(lastBFSIds[0]).toBe(12);
expect(lastBFSIds[1]).toBe(2);
expect(lastBFSIds[2]).toBe(16);
const lastBFSNodes = tree.bfs(node => node);
expect(lastBFSNodes[0].key).toBe(12);
expect(lastBFSNodes[1].key).toBe(2);
expect(lastBFSNodes[2].key).toBe(16);
});
});
describe('AVLTree APIs test', () => {
const avl = new AVLTree<{ id: number; text: string }>();
const avl = new AVLTree<{id: number; text: string}>();
beforeEach(() => {
avl.clear();
});
@ -127,3 +236,34 @@ describe('AVLTree APIs test', () => {
expect(bfsRes[0]).toBe(2);
});
});
describe('AVLTree', () => {
it('should balance the tree using _balanceLR when nodes are added', () => {
const avlTree = new AVLTree();
avlTree.add(10, 'A');
avlTree.add(5, 'B');
avlTree.add(15, 'C');
avlTree.add(3, 'D');
avlTree.add(7, 'E');
// Adding nodes to trigger _balanceLR
avlTree.add(12, 'F');
// You can add more specific assertions to check the tree's balance and structure.
});
it('should balance the tree using _balanceLR when nodes are deleted', () => {
const avlTree = new AVLTree();
avlTree.add(10, 'A');
avlTree.add(5, 'B');
avlTree.add(15, 'C');
avlTree.add(3, 'D');
avlTree.add(7, 'E');
avlTree.add(12, 'F');
// Deleting nodes to trigger _balanceLR
avlTree.delete(3);
// You can add more specific assertions to check the tree's balance and structure.
});
});

View file

@ -71,81 +71,112 @@ describe('BinaryTreeNode', () => {
});
describe('BinaryTree', () => {
let binaryTree: BinaryTree;
let tree: BinaryTree;
beforeEach(() => {
binaryTree = new BinaryTree();
tree = new BinaryTree();
});
afterEach(() => {
binaryTree.clear();
tree.clear();
});
test('should add a node', () => {
const node = binaryTree.add(1);
it('should add a node', () => {
const node = tree.add(1);
expect(node).not.toBeNull();
expect(binaryTree.size).toBe(1);
expect(tree.size).toBe(1);
});
test('should delete a node', () => {
const node = binaryTree.add(1);
expect(binaryTree.size).toBe(1);
it('should delete a node', () => {
const node = tree.add(1);
expect(tree.size).toBe(1);
if (node) {
const result = binaryTree.delete(node);
const result = tree.delete(node, node => node);
expect(result).toHaveLength(1);
expect(binaryTree.size).toBe(0);
expect(tree.size).toBe(0);
}
});
test('should add and find nodes', () => {
binaryTree.add(1);
binaryTree.add(2);
binaryTree.add(3);
it('should add and find nodes', () => {
tree.add(1);
tree.add(2);
tree.add(3);
expect(binaryTree.has(1)).toBe(true);
expect(binaryTree.has(2)).toBe(true);
expect(binaryTree.has(3)).toBe(true);
expect(binaryTree.has(4)).toBe(false);
expect(tree.has(1)).toBe(true);
expect(tree.has(2)).toBe(true);
expect(tree.has(3)).toBe(true);
expect(tree.has(4)).toBe(false);
const node4 = tree.get(4);
expect(tree.has(node4, node => node)).toBe(false);
});
test('should getDepth return correct depth', () => {
binaryTree.add(1);
expect(binaryTree.getDepth(1)).toBe(0);
binaryTree.add(2);
expect(binaryTree.getDepth(2)).toBe(1);
binaryTree.add(3);
expect(binaryTree.getDepth(3, 1)).toBe(1);
binaryTree.add(4);
expect(binaryTree.getDepth(4, 1)).toBe(2);
expect(binaryTree.getDepth(4)).toBe(2);
expect(binaryTree.getDepth(4, 2)).toBe(1);
it('should getDepth return correct depth', () => {
tree.add(1);
expect(tree.getDepth(1)).toBe(0);
tree.add(2);
expect(tree.getDepth(2)).toBe(1);
tree.add(3);
expect(tree.getDepth(3, 1)).toBe(1);
tree.add(4);
expect(tree.getDepth(4, 1)).toBe(2);
expect(tree.getDepth(4)).toBe(2);
expect(tree.getDepth(4, 2)).toBe(1);
});
test('should traverse in-order', () => {
binaryTree.add(4);
binaryTree.add(2);
binaryTree.add(6);
binaryTree.add(1);
binaryTree.add(3);
binaryTree.add(5);
binaryTree.add(7);
it('should traverse in-order', () => {
tree.add(4);
tree.add(2);
tree.add(6);
tree.add(1);
tree.add(3);
tree.add(5);
tree.add(7);
const inOrder = binaryTree.dfs(node => node.key);
const inOrder = tree.dfs(node => node.key);
expect(inOrder).toEqual([1, 2, 3, 4, 5, 6, 7]);
});
test('should clear the tree', () => {
binaryTree.add(1);
binaryTree.add(2);
it('should getLeftMost', () => {
tree.addMany([4, 2, 6, 1, 3, 5, 7]);
expect(binaryTree.size).toBe(2);
const leftMost = tree.getLeftMost(tree.root, IterationType.RECURSIVE);
expect(leftMost?.key).toEqual(1);
const rightMost = tree.getRightMost(tree.root, IterationType.RECURSIVE);
expect(rightMost?.key).toEqual(7);
});
binaryTree.clear();
it('should isSubtreeBST', () => {
tree.addMany([
new BinaryTreeNode(4, 4),
new BinaryTreeNode(2, 2),
new BinaryTreeNode(6, 6),
new BinaryTreeNode(1, 1),
new BinaryTreeNode(3, 3),
new BinaryTreeNode(5, 5),
new BinaryTreeNode(7, 7),
new BinaryTreeNode(4, 4)
]);
expect(binaryTree.size).toBe(0);
expect(binaryTree.root).toBeNull();
expect(tree.isSubtreeBST(tree.get(4), IterationType.RECURSIVE)).toBe(true);
});
it('should subTreeTraverse', () => {
tree.addMany([4, 2, 6, 1, 3, 5, 7]);
expect(tree.subTreeTraverse(node => node.key, tree.get(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]);
});
it('should clear the tree', () => {
tree.add(1);
tree.add(2);
expect(tree.size).toBe(2);
tree.clear();
expect(tree.size).toBe(0);
expect(tree.root).toBeNull();
});
});
@ -200,7 +231,7 @@ describe('BinaryTree Morris Traversal', () => {
});
describe('BinaryTree APIs test', () => {
const avl = new AVLTree<{ id: number; text: string }>();
const avl = new AVLTree<{id: number; text: string}>();
beforeEach(() => {
avl.clear();
});
@ -236,4 +267,195 @@ describe('BinaryTree traversals', () => {
const levels = tree.listLevels(node => node.key);
expect(levels).toEqual([[35], [20, 40], [15, 29, 50], [16, 28, 30, 45, 55]]);
isDebug && console.log(levels);
expect(tree.listLevels(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([
[35],
[20, 40],
[15, 29, 50],
[16, 28, 30, 45, 55]
]);
isDebug && console.log(levels);
});
describe('BinaryTree', () => {
let tree: BinaryTree<string>;
beforeEach(() => {
tree = new BinaryTree<string>();
});
afterEach(() => {
tree.clear();
});
it('should create an empty BinaryTree', () => {
expect(tree.size).toBe(0);
expect(tree.isEmpty()).toBe(true);
expect(tree.root).toBe(null);
});
it('should add nodes to the tree', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
expect(tree.size).toBe(3);
expect(tree.isEmpty()).toBe(false);
expect(tree.root?.key).toBe(5);
});
it('should clear the BinaryTree', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
tree.clear();
expect(tree.size).toBe(0);
expect(tree.isEmpty()).toBe(true);
expect(tree.root).toBe(null);
});
it('should get nodes by key', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
const nodeA = tree.get(5);
const nodeB = tree.get(3);
expect(nodeA?.key).toBe(5);
expect(nodeA?.val).toBe('A');
expect(nodeB?.key).toBe(3);
expect(nodeB?.val).toBe('B');
});
it('should return null when getting a non-existent node', () => {
tree.add(5, 'A');
const node = tree.get(3);
expect(node).toBe(null);
});
it('should get the depth of a node', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
expect(tree.getDepth(7)).toBe(1);
expect(tree.getDepth(3)).toBe(1);
});
it('should get the height of the tree', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
expect(tree.getHeight()).toBe(1);
expect(tree.getHeight(undefined, IterationType.RECURSIVE)).toBe(1);
expect(tree.getMinHeight(undefined, IterationType.RECURSIVE)).toBe(1);
});
it('should check if the tree is a binary search tree', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
expect(tree.isBST()).toBe(true);
});
it('should perform a depth-first traversal', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
const result = tree.dfs();
expect(result).toEqual([3, 5, 7]);
// Add assertions for the result of depth-first traversal
});
it('should perform a breadth-first traversal', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
const result = tree.bfs(node => node.key);
expect(result).toEqual([5, 3, 7]);
// Add assertions for the result of breadth-first traversal
});
it('should list levels of the tree', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
const levels = tree.listLevels();
expect(levels).toEqual([[5], [3, 7]]);
// Add assertions for the levels of the tree
});
it('should delete nodes from the tree', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
tree.delete(3);
expect(tree.size).toBe(2);
expect(tree.get(3)).toBe(null);
});
it('should check if the tree is perfectly balanced', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
expect(tree.isPerfectlyBalanced()).toBe(true);
});
it('should get nodes by a custom callback', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
const nodes = tree.getNodes('B', (node: BinaryTreeNode<string>) => node.val);
expect(nodes.length).toBe(1);
expect(nodes[0].key).toBe(3);
const nodesRec = tree.getNodes(
'B',
(node: BinaryTreeNode<string>) => node.val,
false,
tree.root,
IterationType.RECURSIVE
);
expect(nodesRec.length).toBe(1);
expect(nodesRec[0].key).toBe(3);
});
it('should perform Morris traversal', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
const result = tree.morris();
expect(result).toEqual([3, 5, 7]);
// Add assertions for the result of Morris traversal
});
it('should perform delete all', () => {
tree.add(5, 'A');
tree.add(3, 'B');
tree.add(7, 'C');
tree.delete(5);
tree.delete(7);
tree.delete(3);
expect(tree.root).toBe(null);
expect(tree.getHeight()).toBe(-1);
});
});

View file

@ -1,4 +1,4 @@
import {BST, BSTNode, CP} from '../../../../src';
import {BST, BSTNode, CP, IterationType} from '../../../../src';
import {isDebugTest} from '../../../config';
const isDebug = isDebugTest;
@ -189,7 +189,7 @@ describe('BST operations test', () => {
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objBST = new BST<{ key: number; keyA: number }>();
const objBST = new BST<{key: number; keyA: number}>();
expect(objBST).toBeInstanceOf(BST);
objBST.add(11, {key: 11, keyA: 11});
objBST.add(3, {key: 3, keyA: 3});
@ -260,7 +260,7 @@ describe('BST operations test', () => {
objBST.perfectlyBalance();
expect(objBST.isPerfectlyBalanced()).toBe(true);
const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = [];
const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = [];
objBST.bfs(node => bfsNodesAfterBalanced.push(node));
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
@ -385,7 +385,397 @@ describe('BST operations test', () => {
expect(bfsIDs[1]).toBe(12);
expect(bfsIDs[2]).toBe(16);
const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = [];
const bfsNodes: BSTNode<{key: number; keyA: number}>[] = [];
objBST.bfs(node => bfsNodes.push(node));
expect(bfsNodes[0].key).toBe(2);
expect(bfsNodes[1].key).toBe(12);
expect(bfsNodes[2].key).toBe(16);
});
});
describe('BST operations test recursively', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const bst = new BST({iterationType: IterationType.RECURSIVE});
expect(bst).toBeInstanceOf(BST);
bst.add(11, 11);
bst.add(3, 3);
const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
bst.addMany(idsAndValues, idsAndValues, false);
expect(bst.root).toBeInstanceOf(BSTNode);
if (bst.root) expect(bst.root.key).toBe(11);
expect(bst.size).toBe(16);
expect(bst.has(6)).toBe(true);
const node6 = bst.get(6);
expect(node6 && bst.getHeight(6)).toBe(2);
expect(node6 && bst.getDepth(6)).toBe(3);
const nodeId10 = bst.get(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.get(9, node => node.val);
expect(nodeVal9?.key).toBe(9);
const leftMost = bst.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = bst.get(15);
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
let subTreeSum = 0;
node15 && bst.subTreeTraverse(node => (subTreeSum += node.key), 15);
expect(subTreeSum).toBe(70);
let lesserSum = 0;
bst.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(node15).toBeInstanceOf(BSTNode);
const node11 = bst.get(11);
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = bst.dfs(node => node, 'in');
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
bst.perfectlyBalance();
expect(bst.isPerfectlyBalanced()).toBe(true);
const bfsNodesAfterBalanced: BSTNode<number>[] = [];
bst.bfs(node => bfsNodesAfterBalanced.push(node));
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = bst.delete(11);
expect(removed11).toBeInstanceOf(Array);
expect(removed11[0]).toBeDefined();
expect(removed11[0].deleted).toBeDefined();
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight(15)).toBe(1);
const removed1 = bst.delete(1);
expect(removed1).toBeInstanceOf(Array);
expect(removed1[0]).toBeDefined();
expect(removed1[0].deleted).toBeDefined();
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(4);
const removed4 = bst.delete(4);
expect(removed4).toBeInstanceOf(Array);
expect(removed4[0]).toBeDefined();
expect(removed4[0].deleted).toBeDefined();
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(4);
const removed10 = bst.delete(10);
expect(removed10).toBeInstanceOf(Array);
expect(removed10[0]).toBeDefined();
expect(removed10[0].deleted).toBeDefined();
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(4);
const removed15 = bst.delete(15);
expect(removed15).toBeInstanceOf(Array);
expect(removed15[0]).toBeDefined();
expect(removed15[0].deleted).toBeDefined();
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed5 = bst.delete(5);
expect(removed5).toBeInstanceOf(Array);
expect(removed5[0]).toBeDefined();
expect(removed5[0].deleted).toBeDefined();
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed13 = bst.delete(13);
expect(removed13).toBeInstanceOf(Array);
expect(removed13[0]).toBeDefined();
expect(removed13[0].deleted).toBeDefined();
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed3 = bst.delete(3);
expect(removed3).toBeInstanceOf(Array);
expect(removed3[0]).toBeDefined();
expect(removed3[0].deleted).toBeDefined();
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed8 = bst.delete(8);
expect(removed8).toBeInstanceOf(Array);
expect(removed8[0]).toBeDefined();
expect(removed8[0].deleted).toBeDefined();
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed6 = bst.delete(6);
expect(removed6).toBeInstanceOf(Array);
expect(removed6[0]).toBeDefined();
expect(removed6[0].deleted).toBeDefined();
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
expect(bst.delete(6).length).toBe(0);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed7 = bst.delete(7);
expect(removed7).toBeInstanceOf(Array);
expect(removed7[0]).toBeDefined();
expect(removed7[0].deleted).toBeDefined();
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed9 = bst.delete(9);
expect(removed9).toBeInstanceOf(Array);
expect(removed9[0]).toBeDefined();
expect(removed9[0].deleted).toBeDefined();
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed14 = bst.delete(14);
expect(removed14).toBeInstanceOf(Array);
expect(removed14[0]).toBeDefined();
expect(removed14[0].deleted).toBeDefined();
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(2);
expect(bst.isAVLBalanced()).toBe(false);
const bfsIDs: number[] = [];
bst.bfs(node => bfsIDs.push(node.key));
expect(bfsIDs[0]).toBe(2);
expect(bfsIDs[1]).toBe(12);
expect(bfsIDs[2]).toBe(16);
const bfsNodes: BSTNode<number>[] = [];
bst.bfs(node => bfsNodes.push(node));
expect(bfsNodes[0].key).toBe(2);
expect(bfsNodes[1].key).toBe(12);
expect(bfsNodes[2].key).toBe(16);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objBST = new BST<{key: number; keyA: number}>();
expect(objBST).toBeInstanceOf(BST);
objBST.add(11, {key: 11, keyA: 11});
objBST.add(3, {key: 3, keyA: 3});
const values = [
{key: 15, keyA: 15},
{key: 1, keyA: 1},
{key: 8, keyA: 8},
{key: 13, keyA: 13},
{key: 16, keyA: 16},
{key: 2, keyA: 2},
{key: 6, keyA: 6},
{key: 9, keyA: 9},
{key: 12, keyA: 12},
{key: 14, keyA: 14},
{key: 4, keyA: 4},
{key: 7, keyA: 7},
{key: 10, keyA: 10},
{key: 5, keyA: 5}
];
objBST.addMany(
values.map(item => item.key),
values,
false
);
expect(objBST.root).toBeInstanceOf(BSTNode);
if (objBST.root) expect(objBST.root.key).toBe(11);
expect(objBST.has(6)).toBe(true);
const node6 = objBST.get(6);
expect(node6 && objBST.getHeight(node6)).toBe(2);
expect(node6 && objBST.getDepth(node6)).toBe(3);
const nodeId10 = objBST.get(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = objBST.get(9);
expect(nodeVal9?.key).toBe(9);
const leftMost = objBST.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = objBST.get(15);
expect(node15?.val).toEqual({key: 15, keyA: 15});
const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
let subTreeSum = 0;
node15 && objBST.subTreeTraverse(node => (subTreeSum += node.key), node15);
expect(subTreeSum).toBe(70);
let lesserSum = 0;
objBST.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(node15).toBeInstanceOf(BSTNode);
const node11 = objBST.get(11);
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = objBST.dfs(node => node, 'in');
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
objBST.perfectlyBalance();
expect(objBST.isPerfectlyBalanced()).toBe(true);
const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = [];
objBST.bfs(node => bfsNodesAfterBalanced.push(node));
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = objBST.delete(11);
expect(removed11).toBeInstanceOf(Array);
expect(removed11[0]).toBeDefined();
expect(removed11[0].deleted).toBeDefined();
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
expect(objBST.isAVLBalanced()).toBe(true);
expect(node15 && objBST.getHeight(node15)).toBe(2);
const removed1 = objBST.delete(1);
expect(removed1).toBeInstanceOf(Array);
expect(removed1[0]).toBeDefined();
expect(removed1[0].deleted).toBeDefined();
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(4);
const removed4 = objBST.delete(4);
expect(removed4).toBeInstanceOf(Array);
expect(removed4[0]).toBeDefined();
expect(removed4[0].deleted).toBeDefined();
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(4);
const removed10 = objBST.delete(10);
expect(removed10).toBeInstanceOf(Array);
expect(removed10[0]).toBeDefined();
expect(removed10[0].deleted).toBeDefined();
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(4);
const removed15 = objBST.delete(15);
expect(removed15).toBeInstanceOf(Array);
expect(removed15[0]).toBeDefined();
expect(removed15[0].deleted).toBeDefined();
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
const removed5 = objBST.delete(5);
expect(removed5).toBeInstanceOf(Array);
expect(removed5[0]).toBeDefined();
expect(removed5[0].deleted).toBeDefined();
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
const removed13 = objBST.delete(13);
expect(removed13).toBeInstanceOf(Array);
expect(removed13[0]).toBeDefined();
expect(removed13[0].deleted).toBeDefined();
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
const removed3 = objBST.delete(3);
expect(removed3).toBeInstanceOf(Array);
expect(removed3[0]).toBeDefined();
expect(removed3[0].deleted).toBeDefined();
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
const removed8 = objBST.delete(8);
expect(removed8).toBeInstanceOf(Array);
expect(removed8[0]).toBeDefined();
expect(removed8[0].deleted).toBeDefined();
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
expect(objBST.isAVLBalanced()).toBe(true);
expect(objBST.getHeight()).toBe(3);
const removed6 = objBST.delete(6);
expect(removed6).toBeInstanceOf(Array);
expect(removed6[0]).toBeDefined();
expect(removed6[0].deleted).toBeDefined();
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
expect(objBST.delete(6).length).toBe(0);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
const removed7 = objBST.delete(7);
expect(removed7).toBeInstanceOf(Array);
expect(removed7[0]).toBeDefined();
expect(removed7[0].deleted).toBeDefined();
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
const removed9 = objBST.delete(9);
expect(removed9).toBeInstanceOf(Array);
expect(removed9[0]).toBeDefined();
expect(removed9[0].deleted).toBeDefined();
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(3);
const removed14 = objBST.delete(14);
expect(removed14).toBeInstanceOf(Array);
expect(removed14[0]).toBeDefined();
expect(removed14[0].deleted).toBeDefined();
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
expect(objBST.isAVLBalanced()).toBe(false);
expect(objBST.getHeight()).toBe(2);
expect(objBST.isAVLBalanced()).toBe(false);
const bfsIDs: number[] = [];
objBST.bfs(node => bfsIDs.push(node.key));
expect(bfsIDs[0]).toBe(2);
expect(bfsIDs[1]).toBe(12);
expect(bfsIDs[2]).toBe(16);
const bfsNodes: BSTNode<{key: number; keyA: number}>[] = [];
objBST.bfs(node => bfsNodes.push(node));
expect(bfsNodes[0].key).toBe(2);
expect(bfsNodes[1].key).toBe(12);

View file

@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => {
bfsIDs[0] === 11; // true
expect(bfsIDs[0]).toBe(11);
const objBST = new BST<{ key: number; keyA: number }>();
const objBST = new BST<{key: number; keyA: number}>();
objBST.add(11, {key: 11, keyA: 11});
objBST.add(3, {key: 3, keyA: 3});

View file

@ -1,14 +1,80 @@
// import {RBTree, RBTreeNode} from '../../../../src';
import {RBTree, RBTreeNode} from '../../../../src';
describe('RBTreeNode', () => {
it('should create an instance of RBTreeNode', () => {
const node = new RBTreeNode<number>(1);
expect(node).toBeInstanceOf(RBTreeNode);
});
it('should set and get the ID correctly', () => {
const node = new RBTreeNode<number>(1);
expect(node.key).toBe(1);
node.key = 2;
expect(node.key).toBe(2);
});
it('should set and get the value correctly', () => {
const node: RBTreeNode<number> = new RBTreeNode<number>(1, 42);
expect(node.val).toBe(42);
node.val = 55;
expect(node.val).toBe(55);
});
it('should set and get the left child correctly', () => {
const node1 = new RBTreeNode<number>(1);
const node2 = new RBTreeNode<number>(2);
node1.left = node2;
expect(node1.left).toBe(node2);
expect(node2.parent).toBe(node1);
});
it('should set and get the right child correctly', () => {
const node1 = new RBTreeNode<number>(1);
const node2 = new RBTreeNode<number>(2);
node1.right = node2;
expect(node1.right).toBe(node2);
expect(node2.parent).toBe(node1);
});
it('should set and get the parent correctly', () => {
const node1 = new RBTreeNode<number>(1);
const node2 = new RBTreeNode<number>(2);
node1.left = node2;
expect(node2.parent).toBe(node1);
expect(node1.left).toBe(node2);
});
it('should determine family position correctly', () => {
const root = new RBTreeNode<number>(1);
const leftChild = new RBTreeNode<number>(2);
const rightChild = new RBTreeNode<number>(3);
root.left = leftChild;
root.right = rightChild;
expect(leftChild.familyPosition).toBe('LEFT');
expect(rightChild.familyPosition).toBe('RIGHT');
expect(root.familyPosition).toBe('ROOT');
});
});
describe('Red-Black Tree Tests', () => {
// let tree: RBTree<RBTreeNode<number>>;
//
// beforeEach(() => {
// tree = new RBTree<RBTreeNode<number>>();
// });
let tree: RBTree<RBTreeNode<number>>;
beforeEach(() => {
tree = new RBTree<RBTreeNode<number>>();
});
test('Insertion and In-order Traverse', () => {
// tree.add(5);
tree.add(5);
// tree.add(3);
// tree.add(7);
// tree.add(2);

View file

@ -1,7 +1,8 @@
import {CP, TreeMultiset, TreeMultisetNode} from '../../../../src';
import {CP, IterationType, TreeMultiset, TreeMultisetNode} from '../../../../src';
import {isDebugTest} from '../../../config';
const isDebug = isDebugTest;
describe('TreeMultiset operations test', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const treeMultiset = new TreeMultiset();
@ -206,7 +207,7 @@ describe('TreeMultiset operations test', () => {
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>();
const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>();
expect(objTreeMultiset).toBeInstanceOf(TreeMultiset);
objTreeMultiset.add(11, {key: 11, keyA: 11});
objTreeMultiset.add(3, {key: 3, keyA: 3});
@ -239,196 +240,250 @@ describe('TreeMultiset operations test', () => {
expect(objTreeMultiset.count).toBe(16);
expect(objTreeMultiset.has(6)).toBe(true);
});
});
// const node6 = objTreeMultiset.get(6);
// expect(node6 && objTreeMultiset.getHeight(node6)).toBe(2);
// expect(node6 && objTreeMultiset.getDepth(node6)).toBe(3);
//
// const nodeId10 = objTreeMultiset.get(10, 'key');
// expect(nodeId10?.key).toBe(10);
//
// const nodeVal9 = objTreeMultiset.get(9, 'key');
// expect(nodeVal9?.key).toBe(9);
//
// const nodesByCount1 = objTreeMultiset.getNodesByCount(1);
// expect(nodesByCount1.length).toBe(16);
//
// const leftMost = objTreeMultiset.getLeftMost();
// expect(leftMost?.key).toBe(1);
//
// const node15 = objTreeMultiset.get(15);
// expect(node15?.val).toEqual({key: 15, keyA: 15});
// const minNodeBySpecificNode = node15 && objTreeMultiset.getLeftMost(node15);
// expect(minNodeBySpecificNode?.key).toBe(12);
//
// const subTreeSum = node15 && objTreeMultiset.subTreeSum(node15);
// expect(subTreeSum).toBe(70);
//
// const lesserSum = objTreeMultiset.lesserSum(10);
// expect(lesserSum).toBe(45);
//
// expect(node15).toBeInstanceOf(TreeMultisetNode);
// if (node15 instanceof TreeMultisetNode) {
// const subTreeAdd = objTreeMultiset.subTreeAddCount(node15, 1);
// expect(subTreeAdd).toBeDefined();
// }
//
// const node11 = objTreeMultiset.get(11);
// expect(node11).toBeInstanceOf(TreeMultisetNode);
// if (node11 instanceof TreeMultisetNode) {
// const allGreaterNodesAdded = objTreeMultiset.allGreaterNodesAddCount(node11, 2);
// expect(allGreaterNodesAdded).toBeDefined();
// }
//
// const dfsInorderNodes = objTreeMultiset.dfs(node => node, 'in');
// expect(dfsInorderNodes[0].key).toBe(1);
// expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
//
// objTreeMultiset.perfectlyBalance();
// expect(objTreeMultiset.isPerfectlyBalanced()).toBe(true);
//
// const bfsNodesAfterBalanced = objTreeMultiset.bfs('node');
// expect(bfsNodesAfterBalanced[0].key).toBe(8);
// expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
//
// const removed11 = objTreeMultiset.delete(11, true);
// expect(removed11).toBeInstanceOf(Array);
// expect(removed11[0]).toBeDefined();
// expect(removed11[0].deleted).toBeDefined();
//
// if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
//
// expect(node15 && objTreeMultiset.getHeight(node15)).toBe(2);
//
// const removed1 = objTreeMultiset.delete(1, true);
// expect(removed1).toBeInstanceOf(Array);
// expect(removed1[0]).toBeDefined();
// expect(removed1[0].deleted).toBeDefined();
// if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
//
// expect(objTreeMultiset.getHeight()).toBe(4);
//
// const removed4 = objTreeMultiset.delete(4, true);
// expect(removed4).toBeInstanceOf(Array);
// expect(removed4[0]).toBeDefined();
// expect(removed4[0].deleted).toBeDefined();
// if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(4);
//
// const removed10 = objTreeMultiset.delete(10, true);
// expect(removed10).toBeInstanceOf(Array);
// expect(removed10[0]).toBeDefined();
// expect(removed10[0].deleted).toBeDefined();
// if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(4);
//
// const removed15 = objTreeMultiset.delete(15, true);
// expect(removed15).toBeInstanceOf(Array);
// expect(removed15[0]).toBeDefined();
// expect(removed15[0].deleted).toBeDefined();
// if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed5 = objTreeMultiset.delete(5, true);
// expect(removed5).toBeInstanceOf(Array);
// expect(removed5[0]).toBeDefined();
// expect(removed5[0].deleted).toBeDefined();
// if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed13 = objTreeMultiset.delete(13, true);
// expect(removed13).toBeInstanceOf(Array);
// expect(removed13[0]).toBeDefined();
// expect(removed13[0].deleted).toBeDefined();
// if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed3 = objTreeMultiset.delete(3, true);
// expect(removed3).toBeInstanceOf(Array);
// expect(removed3[0]).toBeDefined();
// expect(removed3[0].deleted).toBeDefined();
// if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed8 = objTreeMultiset.delete(8, true);
// expect(removed8).toBeInstanceOf(Array);
// expect(removed8[0]).toBeDefined();
// expect(removed8[0].deleted).toBeDefined();
// if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed6 = objTreeMultiset.delete(6, true);
// expect(removed6).toBeInstanceOf(Array);
// expect(removed6[0]).toBeDefined();
// expect(removed6[0].deleted).toBeDefined();
// if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
// expect(objTreeMultiset.delete(6, true).length).toBe(0);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed7 = objTreeMultiset.delete(7, true);
// expect(removed7).toBeInstanceOf(Array);
// expect(removed7[0]).toBeDefined();
// expect(removed7[0].deleted).toBeDefined();
// if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed9 = objTreeMultiset.delete(9, true);
// expect(removed9).toBeInstanceOf(Array);
// expect(removed9[0]).toBeDefined();
// expect(removed9[0].deleted).toBeDefined();
// if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(3);
//
// const removed14 = objTreeMultiset.delete(14, true);
// expect(removed14).toBeInstanceOf(Array);
// expect(removed14[0]).toBeDefined();
// expect(removed14[0].deleted).toBeDefined();
// if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
// expect(objTreeMultiset.getHeight()).toBe(2);
//
//
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
//
// const bfsIDs = objTreeMultiset.bfs();
// expect(bfsIDs[0]).toBe(2);
// expect(bfsIDs[1]).toBe(12);
// expect(bfsIDs[2]).toBe(16);
//
// const bfsNodes = objTreeMultiset.bfs('node');
// expect(bfsNodes[0].key).toBe(2);
// expect(bfsNodes[1].key).toBe(12);
// expect(bfsNodes[2].key).toBe(16);
//
// expect(objTreeMultiset.count).toBe(5);
describe('TreeMultiset operations test recursively', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const treeMultiset = new TreeMultiset({iterationType: IterationType.RECURSIVE});
expect(treeMultiset instanceof TreeMultiset);
treeMultiset.add(11, 11);
treeMultiset.add(3, 3);
const idAndValues = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
treeMultiset.addMany(idAndValues, idAndValues);
expect(treeMultiset.root instanceof TreeMultisetNode);
if (treeMultiset.root) expect(treeMultiset.root.key == 11);
expect(treeMultiset.size).toBe(16);
expect(treeMultiset.count).toBe(18);
expect(treeMultiset.has(6));
expect(treeMultiset.getHeight(6)).toBe(3);
expect(treeMultiset.getDepth(6)).toBe(1);
const nodeId10 = treeMultiset.get(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultiset.get(9, node => node.val);
expect(nodeVal9?.key).toBe(9);
const nodesByCount1 = treeMultiset.getNodes(1, node => node.count);
expect(nodesByCount1.length).toBe(14);
const nodesByCount2 = treeMultiset.getNodes(2, node => node.count);
expect(nodesByCount2.length).toBe(2);
const leftMost = treeMultiset.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = treeMultiset.get(15);
const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
let subTreeSum = 0;
node15 && treeMultiset.subTreeTraverse((node: TreeMultisetNode<number>) => (subTreeSum += node.key), 15);
expect(subTreeSum).toBe(70);
let lesserSum = 0;
treeMultiset.lesserOrGreaterTraverse((node: TreeMultisetNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(node15 instanceof TreeMultisetNode);
if (node15 instanceof TreeMultisetNode) {
const subTreeAdd = treeMultiset.subTreeTraverse((node: TreeMultisetNode<number>) => (node.count += 1), 15);
expect(subTreeAdd);
}
const node11 = treeMultiset.get(11);
expect(node11 instanceof TreeMultisetNode);
if (node11 instanceof TreeMultisetNode) {
const allGreaterNodesAdded = treeMultiset.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11);
expect(allGreaterNodesAdded);
}
const dfsInorderNodes = treeMultiset.dfs(node => node, 'in');
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
expect(treeMultiset.isPerfectlyBalanced()).toBe(false);
treeMultiset.perfectlyBalance();
expect(treeMultiset.isPerfectlyBalanced()).toBe(true);
expect(treeMultiset.isAVLBalanced()).toBe(true);
const bfsNodesAfterBalanced = treeMultiset.bfs(node => node);
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = treeMultiset.delete(11, undefined, true);
expect(removed11 instanceof Array);
expect(removed11[0]);
expect(removed11[0].deleted);
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight(15)).toBe(1);
const removed1 = treeMultiset.delete(1, undefined, true);
expect(removed1 instanceof Array);
expect(removed1[0]);
expect(removed1[0].deleted);
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(4);
const removed4 = treeMultiset.delete(4, undefined, true);
expect(removed4 instanceof Array);
expect(removed4[0]);
expect(removed4[0].deleted);
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(4);
const removed10 = treeMultiset.delete(10, undefined, true);
expect(removed10 instanceof Array);
expect(removed10[0]);
expect(removed10[0].deleted);
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed15 = treeMultiset.delete(15, undefined, true);
expect(removed15 instanceof Array);
expect(removed15[0]);
expect(removed15[0].deleted);
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed5 = treeMultiset.delete(5, undefined, true);
expect(removed5 instanceof Array);
expect(removed5[0]);
expect(removed5[0].deleted);
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed13 = treeMultiset.delete(13, undefined, true);
expect(removed13 instanceof Array);
expect(removed13[0]);
expect(removed13[0].deleted);
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed3 = treeMultiset.delete(3, undefined, true);
expect(removed3 instanceof Array);
expect(removed3[0]);
expect(removed3[0].deleted);
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed8 = treeMultiset.delete(8, undefined, true);
expect(removed8 instanceof Array);
expect(removed8[0]);
expect(removed8[0].deleted);
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(3);
const removed6 = treeMultiset.delete(6, undefined, true);
expect(removed6 instanceof Array);
expect(removed6[0]);
expect(removed6[0].deleted);
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
expect(treeMultiset.delete(6, undefined, true).length).toBe(0);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(2);
const removed7 = treeMultiset.delete(7, undefined, true);
expect(removed7 instanceof Array);
expect(removed7[0]);
expect(removed7[0].deleted);
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(2);
const removed9 = treeMultiset.delete(9, undefined, true);
expect(removed9 instanceof Array);
expect(removed9[0]);
expect(removed9[0].deleted);
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(2);
const removed14 = treeMultiset.delete(14, undefined, true);
expect(removed14 instanceof Array);
expect(removed14[0]);
expect(removed14[0].deleted);
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
expect(treeMultiset.isAVLBalanced()).toBe(true);
expect(treeMultiset.getHeight()).toBe(1);
expect(treeMultiset.isAVLBalanced()).toBe(true);
const bfsIDs = treeMultiset.bfs(node => node.key);
expect(bfsIDs[0]).toBe(12);
expect(bfsIDs[1]).toBe(2);
expect(bfsIDs[2]).toBe(16);
const bfsNodes = treeMultiset.bfs(node => node);
expect(bfsNodes[0].key).toBe(12);
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultiset.count).toBe(9);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>();
expect(objTreeMultiset).toBeInstanceOf(TreeMultiset);
objTreeMultiset.add(11, {key: 11, keyA: 11});
objTreeMultiset.add(3, {key: 3, keyA: 3});
const values = [
{key: 15, keyA: 15},
{key: 1, keyA: 1},
{key: 8, keyA: 8},
{key: 13, keyA: 13},
{key: 16, keyA: 16},
{key: 2, keyA: 2},
{key: 6, keyA: 6},
{key: 9, keyA: 9},
{key: 12, keyA: 12},
{key: 14, keyA: 14},
{key: 4, keyA: 4},
{key: 7, keyA: 7},
{key: 10, keyA: 10},
{key: 5, keyA: 5}
];
objTreeMultiset.addMany(
values.map(item => item.key),
values
);
expect(objTreeMultiset.root).toBeInstanceOf(TreeMultisetNode);
if (objTreeMultiset.root) expect(objTreeMultiset.root.key).toBe(11);
expect(objTreeMultiset.count).toBe(16);
expect(objTreeMultiset.has(6)).toBe(true);
});
});
describe('TreeMultiset Performance test', function () {
// const treeMS = new TreeMultiset<TreeMultisetNode<number>>();
// const inputSize = [100]; // Adjust input sizes as needed
//
// // Define a function to calculate the expected O(n log n) time
// function expectedTime(n: number): number {
// return n * Math.log(n);
// }
const treeMS = new TreeMultiset<TreeMultisetNode<number>>();
const inputSize = 100000; // Adjust input sizes as needed

View file

@ -22,22 +22,27 @@ describe('DirectedGraph Operation Test', () => {
const vertex1 = new DirectedVertex('A');
const vertex2 = new DirectedVertex('B');
const edge = new DirectedEdge('A', 'B');
edge.src = edge.src;
edge.dest = edge.dest;
graph.addVertex(vertex1);
graph.addVertex(vertex2);
graph.addEdge(edge);
expect(graph.outEdgeMap.size).toBe(1);
expect(graph.inEdgeMap.size).toBe(1);
expect(graph.hasEdge('A', 'B')).toBe(true);
expect(graph.hasEdge('B', 'A')).toBe(false);
});
it('should delete edges', () => {
const vertex1 = new DirectedVertex('A');
const vertex2 = new DirectedVertex('B');
// const vertex2 = new DirectedVertex('B');
graph.createVertex('B');
const edge = new DirectedEdge('A', 'B');
graph.addVertex(vertex1);
graph.addVertex(vertex2);
graph.addVertex('B');
graph.addEdge(edge);
expect(graph.deleteEdge(edge)).toBe(edge);
@ -49,16 +54,41 @@ describe('DirectedGraph Operation Test', () => {
const vertexB = new DirectedVertex('B');
const vertexC = new DirectedVertex('C');
const edgeAB = new DirectedEdge('A', 'B');
const edgeBC = new DirectedEdge('B', 'C');
graph.createEdge('B', 'C');
graph.addVertex(vertexA);
graph.addVertex(vertexB);
graph.addVertex(vertexC);
graph.addEdge(edgeAB);
graph.addEdge(edgeBC);
graph.addEdge('B', 'C');
expect(graph.getEdgeSrc(edgeAB)).toBe(vertexA);
const topologicalOrder = graph.topologicalSort();
if (topologicalOrder) expect(topologicalOrder).toEqual(['A', 'B', 'C']);
graph.deleteEdgesBetween('A', 'B');
const topologicalOrder1 = graph.topologicalSort();
if (topologicalOrder1) expect(topologicalOrder1).toEqual(['B', 'C', 'A']);
expect(graph.incomingEdgesOf(vertexC)?.length).toBe(1);
expect(graph.degreeOf(vertexA)).toBe(0);
expect(graph.inDegreeOf(vertexC)).toBe(1);
expect(graph.outDegreeOf(vertexC)).toBe(0);
expect(graph.edgesOf(vertexC)?.length).toBe(1);
expect(graph.tarjan(true, true, true, true)?.dfnMap.size).toBe(3);
expect(graph.bellmanFord(vertexC, true, true, true)?.paths.length).toBe(3);
expect(graph.getMinPathBetween('B', 'C', true)?.length).toBe(2);
expect(graph.setEdgeWeight('B', 'C', 100)).toBe(true);
expect(graph.getMinCostBetween('B', 'C', true)).toBe(100);
expect(graph.getMinCostBetween('B', 'C')).toBe(1);
expect(graph.getAllPathsBetween('B', 'C')?.length).toBe(1);
expect(graph.deleteVertex(vertexB)).toBe(true);
expect(graph.getAllPathsBetween('B', 'C')?.length).toBe(0);
expect(graph.removeManyVertices([vertexB, vertexC])).toBe(true);
});
});

View file

@ -1,4 +1,4 @@
import {MapGraph, MapVertex} from '../../../../src';
import {MapEdge, MapGraph, MapVertex} from '../../../../src';
describe('MapGraph Operation Test', () => {
it('dijkstra shortest path', () => {
@ -43,3 +43,84 @@ describe('MapGraph Operation Test', () => {
expect(surinToSaanenGoatFarmViaDij?.minDist).toBe(25.2);
});
});
describe('MapGraph', () => {
let mapGraph: MapGraph;
beforeEach(() => {
// Create a new MapGraph instance before each test
mapGraph = new MapGraph([0, 0], [100, 100]);
});
// Test adding vertices to the graph
it('should add vertices to the graph', () => {
const locationA = new MapVertex('A', 10, 20, 'Location A');
const locationB = new MapVertex('B', 30, 40, 'Location B');
mapGraph.addVertex(locationA);
mapGraph.addVertex(locationB);
expect(mapGraph.hasVertex('A')).toBe(true);
expect(mapGraph.hasVertex('B')).toBe(true);
});
// Test adding edges to the graph
it('should add edges to the graph', () => {
const locationA = new MapVertex('A', 10, 20, 'Location A');
const locationB = new MapVertex('B', 30, 40, 'Location B');
const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B');
mapGraph.addVertex(locationA);
mapGraph.addVertex(locationB);
mapGraph.addEdge(edgeAB);
expect(mapGraph.hasEdge('A', 'B')).toBe(true);
});
// Test getting neighbors of a vertex
it('should return the neighbors of a vertex', () => {
const locationA = new MapVertex('A', 10, 20, 'Location A');
locationA.lat = locationA.lat;
locationA.long = locationA.long;
const locationB = mapGraph.createVertex('B', 30, 40, 'Location B');
const locationC = new MapVertex('C', 50, 60, 'Location C');
const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B');
const edgeBC = new MapEdge('B', 'C', 60, 'Edge from B to C');
mapGraph.origin = mapGraph.origin;
mapGraph.bottomRight = mapGraph.bottomRight;
mapGraph.addVertex(locationA);
mapGraph.addVertex(locationB);
mapGraph.addVertex(locationC);
mapGraph.addEdge(edgeAB);
mapGraph.addEdge(edgeBC);
const neighborsOfA = mapGraph.getNeighbors('A');
const neighborsOfB = mapGraph.getNeighbors('B');
expect(neighborsOfA).toEqual([locationB]);
expect(neighborsOfB).toEqual([locationC]);
});
// Test finding the shortest path between locations
it('should find the shortest path between two locations', () => {
const locationA = new MapVertex('A', 10, 20, 'Location A');
const locationB = new MapVertex('B', 30, 40, 'Location B');
const locationC = new MapVertex('C', 50, 60, 'Location C');
const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B');
const edgeBC = new MapEdge('B', 'C', 60, 'Edge from B to C');
mapGraph.addVertex(locationA);
mapGraph.addVertex(locationB);
mapGraph.addVertex(locationC);
mapGraph.addEdge(edgeAB);
mapGraph.addEdge(edgeBC);
const shortestPath = mapGraph.dijkstra('A', 'C');
expect(shortestPath?.minPath.length).toEqual(0);
expect(shortestPath?.distMap.size).toBe(3);
});
});

View file

@ -57,3 +57,85 @@ describe('UndirectedGraph Operation Test', () => {
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key)).toEqual(['A', 'B', 'D']);
});
});
describe('UndirectedGraph', () => {
let undirectedGraph: UndirectedGraph<UndirectedVertex<string>, UndirectedEdge<string>>;
beforeEach(() => {
// Create a new UndirectedGraph instance before each test
undirectedGraph = new UndirectedGraph<UndirectedVertex<string>, UndirectedEdge<string>>();
});
// Test adding vertices to the graph
it('should add vertices to the graph', () => {
const vertexA = new UndirectedVertex('A', 'Location A');
const vertexB = new UndirectedVertex('B', 'Location B');
undirectedGraph.addVertex(vertexA);
undirectedGraph.addVertex(vertexB);
expect(undirectedGraph.hasVertex('A')).toBe(true);
expect(undirectedGraph.hasVertex('B')).toBe(true);
});
// Test adding edges to the graph
it('should add edges to the graph', () => {
const vertexA = new UndirectedVertex('A', 'Location A');
const vertexB = new UndirectedVertex('B', 'Location B');
const edgeAB = new UndirectedEdge('A', 'B', 1, 'Edge between A and B');
undirectedGraph.addVertex(vertexA);
undirectedGraph.addVertex(vertexB);
undirectedGraph.addEdge(edgeAB);
expect(undirectedGraph.hasEdge('A', 'B')).toBe(true);
});
// Test getting neighbors of a vertex
it('should return the neighbors of a vertex', () => {
const vertexA = new UndirectedVertex('A', 'Location A');
const vertexB = new UndirectedVertex('B', 'Location B');
const vertexC = new UndirectedVertex('C', 'Location C');
const edgeAB = new UndirectedEdge('A', 'B', 1, 'Edge between A and B');
const edgeBC = new UndirectedEdge('B', 'C', 2, 'Edge between B and C');
undirectedGraph.addVertex(vertexA);
undirectedGraph.addVertex(vertexB);
undirectedGraph.addVertex(vertexC);
undirectedGraph.addEdge(edgeAB);
undirectedGraph.addEdge(edgeBC);
const neighborsOfA = undirectedGraph.getNeighbors('A');
const neighborsOfB = undirectedGraph.getNeighbors('B');
expect(neighborsOfA).toEqual([vertexB]);
expect(neighborsOfB).toEqual([vertexA, vertexC]);
});
// Test degree of a vertex
it('should return the degree of a vertex', () => {
const vertexA = new UndirectedVertex('A', 'Location A');
const vertexB = new UndirectedVertex('B', 'Location B');
const vertexC = new UndirectedVertex('C', 'Location C');
const edgeAB = new UndirectedEdge('A', 'B', 3, 'Edge between A and B');
const edgeBC = new UndirectedEdge('B', 'C', 4, 'Edge between B and C');
edgeAB.vertices = edgeAB.vertices;
expect(undirectedGraph.edges.size).toBe(0);
undirectedGraph.addVertex(vertexA);
undirectedGraph.addVertex(vertexB);
undirectedGraph.addVertex(vertexC);
undirectedGraph.addEdge(edgeAB);
undirectedGraph.addEdge(edgeBC);
const degreeOfA = undirectedGraph.degreeOf('A');
const degreeOfB = undirectedGraph.degreeOf('B');
const degreeOfC = undirectedGraph.degreeOf('C');
expect(undirectedGraph.edgeSet().length).toBe(2);
expect(undirectedGraph.getEndsOfEdge(edgeBC)?.length).toBe(2);
expect(degreeOfA).toBe(1);
expect(degreeOfB).toBe(2);
expect(degreeOfC).toBe(1);
});
});

View file

@ -22,7 +22,7 @@ describe('Heap Operation Test', () => {
});
it('should object heap work well', function () {
const minHeap = new MinHeap<{ a: string; key: number }>({comparator: (a, b) => a.key - b.key});
const minHeap = new MinHeap<{a: string; key: number}>({comparator: (a, b) => a.key - b.key});
minHeap.add({key: 1, a: 'a1'});
minHeap.add({key: 6, a: 'a6'});
minHeap.add({key: 2, a: 'a2'});
@ -37,7 +37,7 @@ describe('Heap Operation Test', () => {
i++;
}
const maxHeap = new MaxHeap<{ key: number; a: string }>({comparator: (a, b) => b.key - a.key});
const maxHeap = new MaxHeap<{key: number; a: string}>({comparator: (a, b) => b.key - a.key});
maxHeap.add({key: 1, a: 'a1'});
maxHeap.add({key: 6, a: 'a6'});
maxHeap.add({key: 5, a: 'a5'});

View file

@ -3,7 +3,7 @@ import {bigO, magnitude} from '../../../utils';
describe('DoublyLinkedList Operation Test', () => {
let list: DoublyLinkedList<number>;
let objectList: DoublyLinkedList<{ keyA: number }>;
let objectList: DoublyLinkedList<{keyA: number}>;
beforeEach(() => {
list = new DoublyLinkedList();

View file

@ -3,10 +3,10 @@ import {bigO, magnitude} from '../../../utils';
describe('SinglyLinkedList Operation Test', () => {
let list: SinglyLinkedList<number>;
let objectList: SinglyLinkedList<{ keyA: number }>;
let objectList: SinglyLinkedList<{keyA: number}>;
beforeEach(() => {
list = new SinglyLinkedList<number>();
objectList = new SinglyLinkedList<{ keyA: number }>();
objectList = new SinglyLinkedList<{keyA: number}>();
});
describe('push', () => {
@ -393,7 +393,7 @@ describe('SinglyLinkedList Performance Test', () => {
}
// expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR);
expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR * 300);
expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR * 400);
});
});
describe('SinglyLinkedList', () => {

View file

@ -1,5 +1,7 @@
import {Matrix2D, Vector2D} from '../../../../src';
import {isDebugTest} from '../../../config';
const isDebug = isDebugTest;
describe('Matrix2D', () => {
it('should initialize with default identity matrix', () => {
const matrix = new Matrix2D();
@ -136,3 +138,208 @@ describe('Matrix2D', () => {
expect(result.m).toEqual(expectedMatrix);
});
});
describe('Vector2D', () => {
it('should create a vector with default values', () => {
const vector = new Vector2D();
expect(vector.x).toBe(0);
expect(vector.y).toBe(0);
expect(vector.w).toBe(1);
});
it('should correctly calculate vector length', () => {
const vector = new Vector2D(3, 4);
expect(vector.length).toBe(5);
});
it('should correctly add two vectors', () => {
const vector1 = new Vector2D(2, 3);
const vector2 = new Vector2D(1, 2);
const result = Vector2D.add(vector1, vector2);
expect(result.x).toBe(3);
expect(result.y).toBe(5);
});
// Add more test cases for Vector2D methods
});
describe('Matrix2D', () => {
it('should create an identity matrix by default', () => {
const matrix = new Matrix2D();
expect(matrix.m).toEqual(Matrix2D.identity);
});
it('should correctly add two matrices', () => {
const matrix1 = new Matrix2D([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]);
const matrix2 = new Matrix2D([
[9, 8, 7],
[6, 5, 4],
[3, 2, 1]
]);
const result = Matrix2D.add(matrix1, matrix2);
expect(result.m).toEqual([
[10, 10, 10],
[10, 10, 10],
[10, 10, 10]
]);
});
// Add more test cases for Matrix2D methods
});
describe('Matrix2D', () => {
it('should create a matrix with default identity values', () => {
const matrix = new Matrix2D();
expect(matrix.m).toEqual(Matrix2D.identity);
});
it('should create a matrix from a Vector2D', () => {
const vector = new Vector2D(2, 3);
const matrix = new Matrix2D(vector);
expect(matrix.m).toEqual([
[2, 0, 0],
[3, 1, 0],
[1, 0, 1]
]);
});
it('should correctly add two matrices', () => {
const matrix1 = new Matrix2D([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]);
const matrix2 = new Matrix2D([
[9, 8, 7],
[6, 5, 4],
[3, 2, 1]
]);
const result = Matrix2D.add(matrix1, matrix2);
expect(result.m).toEqual([
[10, 10, 10],
[10, 10, 10],
[10, 10, 10]
]);
});
it('should correctly subtract two matrices', () => {
const matrix1 = new Matrix2D([
[5, 4, 3],
[2, 1, 0],
[0, 1, 2]
]);
const matrix2 = new Matrix2D([
[4, 3, 2],
[1, 0, 1],
[2, 1, 0]
]);
const result = Matrix2D.subtract(matrix1, matrix2);
expect(result.m).toEqual([
[1, 1, 1],
[1, 1, -1],
[-2, 0, 2]
]);
});
it('should correctly multiply two matrices', () => {
const matrix1 = new Matrix2D([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]);
const matrix2 = new Matrix2D([
[9, 8, 7],
[6, 5, 4],
[3, 2, 1]
]);
const result = Matrix2D.multiply(matrix1, matrix2);
expect(result.m).toEqual([
[30, 24, 18],
[84, 69, 54],
[138, 114, 90]
]);
});
it('should correctly multiply a matrix by a value', () => {
const matrix = new Matrix2D([
[2, 3, 4],
[5, 6, 7],
[8, 9, 10]
]);
const value = 2;
const result = Matrix2D.multiplyByValue(matrix, value);
expect(result.m).toEqual([
[4, 6, 8],
[10, 12, 14],
[16, 18, 20]
]);
});
it('should correctly multiply a matrix by a vector', () => {
const matrix = new Matrix2D([
[2, 3, 4],
[5, 6, 7],
[8, 9, 10]
]);
const vector = new Vector2D(2, 3);
const result = Matrix2D.multiplyByVector(matrix, vector);
isDebug && console.log(JSON.stringify(result));
expect(result).toEqual({x: 17, y: 35, w: 1});
});
it('should correctly create a view matrix', () => {
const width = 800;
const height = 600;
const viewMatrix = Matrix2D.view(width, height);
expect(viewMatrix.m).toEqual([
[1, 0, 400],
[0, -1, 300],
[0, 0, 1]
]);
});
it('should correctly scale a matrix', () => {
const factor = 3;
const scaledMatrix = Matrix2D.scale(factor);
expect(scaledMatrix.m).toEqual([
[3, 0, 0],
[0, 3, 0],
[0, 0, 3]
]);
});
it('should correctly rotate a matrix', () => {
const radians = Math.PI / 4; // 45 degrees
const rotationMatrix = Matrix2D.rotate(radians);
console.log(JSON.stringify(rotationMatrix.m));
expect(rotationMatrix.m).toEqual([
[0.7071067811865476, -0.7071067811865475, 0],
[0.7071067811865475, 0.7071067811865476, 0],
[0, 0, 1]
]);
});
it('should correctly translate a matrix', () => {
const translationVector = new Vector2D(2, 3);
const translationMatrix = Matrix2D.translate(translationVector);
expect(translationMatrix.m).toEqual([
[1, 0, 2],
[0, 1, 3],
[0, 0, 1]
]);
});
it('should correctly convert a matrix to a vector', () => {
const matrix = new Matrix2D([
[2, 3, 4],
[5, 6, 7],
[8, 9, 10]
]);
const vector = matrix.toVector();
expect(vector).toEqual(new Vector2D(2, 5));
});
});

View file

@ -1,5 +1,7 @@
import {Character, Navigator, NavigatorParams, Turning} from '../../../../src';
import {isDebugTest} from '../../../config';
const isDebug = isDebugTest;
const exampleMatrix: number[][] = [
[0, 0, 0, 0],
[0, 1, 1, 0],
@ -17,7 +19,7 @@ const exampleTurning: Turning = {
// Create a sample move callback function
const exampleOnMove = () => {
expect(true).toBeTruthy();
// console.log(`Moved to position (${cur[0]}, ${cur[1]})`);
// isDebug && console.log(`Moved to position (${cur[0]}, ${cur[1]})`);
};
// Create an initial parameter object for the example
@ -77,3 +79,166 @@ describe('Navigator class', () => {
expect(navigator.check('left')).toBe(false); // Open path
});
});
describe('Navigator', () => {
it('should correctly navigate the grid', () => {
// Define a sample grid and initial parameters
const matrix: number[][] = [
[0, 0, 1],
[0, 1, 0],
[0, 0, 0]
];
const turning: Turning = {
up: 'right',
right: 'down',
down: 'left',
left: 'up'
};
const init: NavigatorParams<number>['init'] = {
cur: [0, 0], // Initial position
charDir: 'right', // Initial character direction
VISITED: 2 // Value to mark visited cells
};
// Initialize the navigator
const navigator = new Navigator({
matrix,
turning,
init,
onMove: cur => cur
});
// Define a function to track visited cells
const visitedCells: number[][] = [];
const onMove = (cur: number[]) => {
visitedCells.push([...cur]);
};
// Attach the onMove function
navigator.onMove = onMove;
// Start the navigation
navigator.start();
// The character should have navigated the grid correctly
expect(visitedCells).toEqual([
[0, 1],
[0, 2],
[1, 2],
[2, 2],
[2, 1],
[2, 0],
[1, 0],
[1, 1]
]);
});
it('should not move if there are no valid moves', () => {
// Define a sample grid with no valid moves
const matrix: number[][] = [
[1, 1],
[1, 1]
];
const turning: Turning = {
up: 'right',
right: 'down',
down: 'left',
left: 'up'
};
const init: NavigatorParams<number>['init'] = {
cur: [0, 0], // Initial position
charDir: 'right', // Initial character direction
VISITED: 2 // Value to mark visited cells
};
// Initialize the navigator
const navigator = new Navigator({
matrix,
turning,
init,
onMove: cur => cur
});
// Define a function to track visited cells
const visitedCells: number[][] = [];
const onMove = (cur: number[]) => {
visitedCells.push([...cur]);
};
// Attach the onMove function
navigator.onMove = onMove;
// Start the navigation
navigator.start();
// The character should not move
isDebug && console.log(visitedCells);
expect(visitedCells).toEqual([
[0, 1],
[1, 1],
[1, 0]
]);
});
it('should handle edge cases and turns correctly', () => {
// Define a sample grid with turns and edge cases
const matrix: number[][] = [
[1, 0, 0, 0],
[1, 0, 1, 0],
[0, 0, 1, 1]
];
const turning: Turning = {
up: 'right',
right: 'down',
down: 'left',
left: 'up'
};
const init: NavigatorParams<number>['init'] = {
cur: [0, 0], // Initial position
charDir: 'right', // Initial character direction
VISITED: 2 // Value to mark visited cells
};
// Initialize the navigator
const navigator = new Navigator({
matrix,
turning,
init,
onMove: cur => cur
});
// Define a function to track visited cells
const visitedCells: number[][] = [];
const onMove = (cur: number[]) => {
visitedCells.push([...cur]);
};
// Attach the onMove function
navigator.onMove = onMove;
// Start the navigation
navigator.start();
// The character should have navigated the grid, handled turns, and edge cases
isDebug && console.log(visitedCells);
expect(visitedCells).toEqual([
[0, 1],
[0, 2],
[0, 3],
[1, 3],
[2, 3],
[2, 2],
[2, 1],
[2, 0],
[1, 0],
[1, 1],
[1, 2]
]);
});
});

View file

@ -0,0 +1,171 @@
import {Vector2D} from '../../../../src';
describe('Vector2D', () => {
it('should create a vector with default values', () => {
const vector = new Vector2D();
expect(vector.x).toBe(0);
expect(vector.y).toBe(0);
expect(vector.w).toBe(1);
});
it('should correctly check if a vector is zero', () => {
const nonZeroVector = new Vector2D(3, 4);
const zeroVector = new Vector2D(0, 0);
expect(nonZeroVector.isZero).toBe(false);
expect(zeroVector.isZero).toBe(true);
});
it('should correctly calculate vector length', () => {
const vector = new Vector2D(3, 4);
expect(vector.length).toBe(5);
});
it('should correctly calculate squared vector length', () => {
const vector = new Vector2D(3, 4);
expect(vector.lengthSq).toBe(25);
});
it('should correctly round vector components', () => {
const vector = new Vector2D(3.6, 4.3);
const roundedVector = vector.rounded;
expect(roundedVector.x).toBe(4);
expect(roundedVector.y).toBe(4);
});
it('should correctly add two vectors', () => {
const vector1 = new Vector2D(2, 3);
const vector2 = new Vector2D(1, 2);
const result = Vector2D.add(vector1, vector2);
expect(result.x).toBe(3);
expect(result.y).toBe(5);
});
it('should correctly subtract two vectors', () => {
const vector1 = new Vector2D(4, 5);
const vector2 = new Vector2D(1, 2);
const result = Vector2D.subtract(vector1, vector2);
expect(result.x).toBe(3);
expect(result.y).toBe(3);
});
it('should correctly subtract value from a vector', () => {
const vector = new Vector2D(5, 7);
const result = Vector2D.subtractValue(vector, 3);
expect(result.x).toBe(2);
expect(result.y).toBe(4);
});
it('should correctly multiply a vector by a value', () => {
const vector = new Vector2D(2, 3);
const result = Vector2D.multiply(vector, 4);
expect(result.x).toBe(8);
expect(result.y).toBe(12);
});
it('should correctly divide a vector by a value', () => {
const vector = new Vector2D(6, 8);
const result = Vector2D.divide(vector, 2);
expect(result.x).toBe(3);
expect(result.y).toBe(4);
});
it('should correctly check if two vectors are equal', () => {
const vector1 = new Vector2D(3, 4);
const vector2 = new Vector2D(3, 4);
const vector3 = new Vector2D(4, 5);
expect(Vector2D.equals(vector1, vector2)).toBe(true);
expect(Vector2D.equals(vector1, vector3)).toBe(false);
});
it('should correctly check if two vectors are equal within a rounding factor', () => {
const vector1 = new Vector2D(3, 4);
const vector2 = new Vector2D(2.9, 3.9);
const vector3 = new Vector2D(4, 5);
expect(Vector2D.equalsRounded(vector1, vector2, 0.2)).toBe(true);
expect(Vector2D.equalsRounded(vector1, vector3, 0.2)).toBe(false);
});
it('should correctly normalize a vector', () => {
const vector = new Vector2D(3, 4);
const normalized = Vector2D.normalize(vector);
expect(normalized.x).toBeCloseTo(0.6);
expect(normalized.y).toBeCloseTo(0.8);
});
it('should correctly truncate a vector', () => {
const vector = new Vector2D(3, 4);
const truncated = Vector2D.truncate(vector, 4);
expect(truncated.length).toBeLessThanOrEqual(4);
});
it('should correctly get the perpendicular vector', () => {
const vector = new Vector2D(3, 4);
const perpendicular = Vector2D.perp(vector);
expect(Vector2D.dot(vector, perpendicular)).toBe(0);
});
it('should correctly reverse the vector', () => {
const vector = new Vector2D(3, 4);
const reversed = Vector2D.reverse(vector);
expect(reversed.x).toBe(-3);
expect(reversed.y).toBe(-4);
});
it('should correctly get the absolute vector', () => {
const vector = new Vector2D(-3, 4);
const absVector = Vector2D.abs(vector);
expect(absVector.x).toBe(3);
expect(absVector.y).toBe(4);
});
it('should correctly calculate the dot product of two vectors', () => {
const vector1 = new Vector2D(2, 3);
const vector2 = new Vector2D(4, 5);
const dotProduct = Vector2D.dot(vector1, vector2);
expect(dotProduct).toBe(23);
});
it('should correctly calculate the distance between two vectors', () => {
const vector1 = new Vector2D(1, 1);
const vector2 = new Vector2D(4, 5);
const distance = Vector2D.distance(vector1, vector2);
expect(distance).toBeCloseTo(5);
});
it('should correctly calculate the squared distance between two vectors', () => {
const vector1 = new Vector2D(1, 1);
const vector2 = new Vector2D(4, 5);
const distanceSq = Vector2D.distanceSq(vector1, vector2);
expect(distanceSq).toBe(25);
});
it('should correctly determine the sign of the cross product of two vectors', () => {
const vector1 = new Vector2D(2, 3);
const vector2 = new Vector2D(4, 5);
const sign = Vector2D.sign(vector1, vector2);
expect(sign).toBe(-1); // Assuming specific vector values, the result may vary
});
it('should correctly calculate the angle between a vector and the negative y-axis', () => {
const vector = new Vector2D(3, 4);
const angle = Vector2D.angle(vector);
expect(angle).toBeCloseTo(2.498091544796509, 3);
});
it('should create a random vector within the specified range', () => {
const maxX = 10;
const maxY = 10;
const randomVector = Vector2D.random(maxX, maxY);
expect(randomVector.x).toBeGreaterThanOrEqual(-maxX / 2);
expect(randomVector.x).toBeLessThanOrEqual(maxX / 2);
expect(randomVector.y).toBeGreaterThanOrEqual(-maxY / 2);
expect(randomVector.y).toBeLessThanOrEqual(maxY / 2);
});
it('should zero the vector components', () => {
const vector = new Vector2D(3, 4);
vector.zero();
expect(vector.x).toBe(0);
expect(vector.y).toBe(0);
});
});

View file

@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => {
});
it('should add elements and maintain heap property in a object MaxPriorityQueue', () => {
const priorityQueue = new MaxPriorityQueue<{ keyA: number }>({comparator: (a, b) => b.keyA - a.keyA});
const priorityQueue = new MaxPriorityQueue<{keyA: number}>({comparator: (a, b) => b.keyA - a.keyA});
priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]);
priorityQueue.add({keyA: 7});
@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => {
it('should correctly heapify an object array', () => {
const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}];
const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA});
const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA});
expect(maxPQ.poll()?.keyA).toBe(7);
expect(maxPQ.poll()?.keyA).toBe(5);

View file

@ -1,6 +1,8 @@
import {ArrayDeque, Deque, ObjectDeque} from '../../../../src';
import {bigO} from '../../../utils';
import {isDebugTest} from '../../../config';
const isDebug = isDebugTest;
describe('Deque Tests', () => {
// Test cases for the Deque class (DoublyLinkedList-based)
describe('Deque (DoublyLinkedList-based)', () => {
@ -141,7 +143,268 @@ describe('Deque Performance Test', () => {
for (let i = 0; i < dataSize; i++) {
queue.pop();
}
console.log(`Queue Deque Test: ${performance.now() - startTime} ms`);
isDebug && console.log(`Queue Deque Test: ${performance.now() - startTime} ms`);
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
});
});
describe('Deque', () => {
let deque: Deque<number>;
beforeEach(() => {
deque = new Deque<number>();
});
test('should initialize an empty deque', () => {
expect(deque.size).toBe(0);
expect(deque.isEmpty()).toBe(true);
});
test('should add elements to the front and back', () => {
deque.addFirst(1);
deque.addLast(2);
expect(deque.size).toBe(2);
expect(deque.peekFirst()).toBe(1);
expect(deque.peekLast()).toBe(2);
});
test('should remove elements from the front and back', () => {
deque.addFirst(1);
deque.addLast(2);
const firstElement = deque.pollFirst();
const lastElement = deque.pollLast();
expect(deque.size).toBe(0);
expect(firstElement).toBe(1);
expect(lastElement).toBe(2);
});
test('should get elements by index', () => {
deque.addLast(1);
deque.addLast(2);
deque.addLast(3);
expect(deque.getAt(0)).toBe(1);
expect(deque.getAt(1)).toBe(2);
expect(deque.getAt(2)).toBe(3);
});
test('should return null for out-of-bounds index', () => {
expect(deque.getAt(0)).toBe(undefined);
expect(deque.getAt(1)).toBe(undefined);
expect(deque.getAt(-1)).toBe(undefined);
});
test('should check if the deque is empty', () => {
expect(deque.isEmpty()).toBe(true);
deque.addLast(1);
expect(deque.isEmpty()).toBe(false);
deque.pollFirst();
expect(deque.isEmpty()).toBe(true);
});
});
describe('ArrayDeque', () => {
let deque: ArrayDeque<number>;
beforeEach(() => {
deque = new ArrayDeque<number>();
});
test('should initialize an empty deque', () => {
expect(deque.size).toBe(0);
expect(deque.isEmpty()).toBe(true);
});
test('should add elements to the front and back', () => {
deque.addFirst(1);
deque.addLast(2);
expect(deque.size).toBe(2);
expect(deque.peekFirst()).toBe(1);
expect(deque.peekLast()).toBe(2);
});
test('should remove elements from the front and back', () => {
deque.addFirst(1);
deque.addLast(2);
const firstElement = deque.pollFirst();
const lastElement = deque.pollLast();
expect(deque.size).toBe(0);
expect(firstElement).toBe(1);
expect(lastElement).toBe(2);
});
test('should get elements by index', () => {
deque.addLast(1);
deque.addLast(2);
deque.addLast(3);
expect(deque.get(0)).toBe(1);
expect(deque.get(1)).toBe(2);
expect(deque.get(2)).toBe(3);
});
test('should return null for out-of-bounds index', () => {
expect(deque.get(0)).toBe(null);
expect(deque.get(1)).toBe(null);
expect(deque.get(-1)).toBe(null);
});
test('should check if the deque is empty', () => {
expect(deque.isEmpty()).toBe(true);
deque.addLast(1);
expect(deque.isEmpty()).toBe(false);
deque.pollFirst();
expect(deque.isEmpty()).toBe(true);
});
test('should set elements at a specific index', () => {
deque.addLast(1);
deque.addLast(2);
deque.addLast(3);
deque.set(1, 4);
expect(deque.get(0)).toBe(1);
expect(deque.get(1)).toBe(4);
expect(deque.get(2)).toBe(3);
});
test('should insert elements at a specific index', () => {
deque.addLast(1);
deque.addLast(2);
deque.addLast(3);
deque.insert(1, 4);
expect(deque.size).toBe(4);
expect(deque.get(0)).toBe(1);
expect(deque.get(1)).toBe(4);
expect(deque.get(2)).toBe(2);
expect(deque.get(3)).toBe(3);
});
test('should delete elements at a specific index', () => {
deque.addLast(1);
deque.addLast(2);
deque.addLast(3);
const deletedElement = deque.delete(1);
expect(deque.size).toBe(2);
expect(deletedElement[0]).toBe(2);
expect(deque.get(0)).toBe(1);
expect(deque.get(1)).toBe(3);
});
});
describe('ObjectDeque', () => {
let deque: ObjectDeque<number>;
beforeEach(() => {
deque = new ObjectDeque<number>();
});
test('should add elements to the front of the deque', () => {
deque.addFirst(1);
deque.addFirst(2);
expect(deque.size).toBe(2);
expect(deque.peekFirst()).toBe(2);
expect(deque.peekLast()).toBe(1);
});
test('should add elements to the end of the deque', () => {
deque.addLast(1);
deque.addLast(2);
expect(deque.size).toBe(2);
expect(deque.peekFirst()).toBe(1);
expect(deque.peekLast()).toBe(2);
});
test('should remove elements from the front of the deque', () => {
deque.addLast(1);
deque.addLast(2);
const removedElement = deque.pollFirst();
expect(deque.size).toBe(1);
expect(removedElement).toBe(1);
expect(deque.peekFirst()).toBe(2);
});
test('should remove elements from the end of the deque', () => {
deque.addLast(1);
deque.addLast(2);
const removedElement = deque.pollFirst();
expect(deque.size).toBe(1);
expect(removedElement).toBe(1);
expect(deque.peekLast()).toBe(2);
});
test('should return the element at the front of the deque without removing it', () => {
deque.addFirst(1);
deque.addFirst(2);
expect(deque.peekFirst()).toBe(2);
expect(deque.size).toBe(2);
});
test('should return the element at the end of the deque without removing it', () => {
deque.addLast(1);
deque.addLast(2);
expect(deque.peekLast()).toBe(2);
expect(deque.size).toBe(2);
});
test('should return the correct size of the deque', () => {
deque.addFirst(1);
deque.addLast(2);
deque.addLast(3);
expect(deque.size).toBe(3);
});
test('should check if the deque is empty', () => {
expect(deque.isEmpty()).toBe(true);
deque.addFirst(1);
expect(deque.isEmpty()).toBe(false);
});
test('should set elements at a specific index', () => {
deque.addFirst(1);
deque.addLast(2);
deque.addLast(3);
expect(deque.peekFirst()).toBe(1);
expect(deque.get(1)).toBe(2);
expect(deque.peekLast()).toBe(3);
});
test('should insert elements at a specific index', () => {
deque.addFirst(1);
deque.addLast(2);
deque.addLast(3);
expect(deque.size).toBe(3);
expect(deque.peekFirst()).toBe(1);
expect(deque.get(1)).toBe(2);
expect(deque.get(2)).toBe(3);
expect(deque.peekLast()).toBe(3);
});
});

View file

@ -1,6 +1,8 @@
import {LinkedListQueue, Queue} from '../../../../src';
import {bigO, magnitude} from '../../../utils';
import {isDebugTest} from '../../../config';
const isDebug = isDebugTest;
describe('Queue Operation Test', () => {
it('should validate a queue', () => {
const queue = new Queue<number>();
@ -209,7 +211,7 @@ describe('Queue Performance Test', () => {
for (let i = 0; i < dataSize; i++) {
queue.dequeue();
}
console.log(`Queue Performance Test: ${performance.now() - startTime} ms`);
isDebug && console.log(`Queue Performance Test: ${performance.now() - startTime} ms`);
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
});

View file

@ -26,7 +26,7 @@ export const bigO = {
function findPotentialN(input: any): number {
let longestArray: any[] = [];
let mostProperties: { [key: string]: any } = {};
let mostProperties: {[key: string]: any} = {};
function recurse(obj: any) {
if (Array.isArray(obj)) {