[rbtree, binary-tree] Further testing of the Red-Black Tree is required. The 'get' method in BinaryTree should be renamed to 'getNode,' and an additional 'get' method should be added.

This commit is contained in:
Revone 2023-11-01 13:48:01 +08:00
parent ea3ab1283e
commit c82190764e
36 changed files with 318 additions and 240 deletions

46
package-lock.json generated
View file

@ -15,17 +15,17 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"auto-changelog": "^2.4.0",
"avl-tree-typed": "^1.40.0",
"avl-tree-typed": "^1.41.0",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.40.0",
"bst-typed": "^1.40.0",
"binary-tree-typed": "^1.41.0",
"bst-typed": "^1.41.0",
"dependency-cruiser": "^14.1.0",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"heap-typed": "^1.40.0",
"heap-typed": "^1.41.0",
"istanbul-badges-readme": "^1.8.5",
"jest": "^29.7.0",
"prettier": "^3.0.3",
@ -2728,12 +2728,12 @@
}
},
"node_modules/avl-tree-typed": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.40.0.tgz",
"integrity": "sha512-Nw2sLCkPmXQWZRJXhQ6BacyWNdX199sjifhdZUOJPLyq9ha+gFzyq2yQCG3+7QrMRCo9JsPIXXSw8PPKPAK2CA==",
"version": "1.41.0",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.41.0.tgz",
"integrity": "sha512-fY0TV30CtWSqLUFeT4fiyrYNSiwXjHL5hObSTE8D8ngWxLsL4QPGVL5lA3VXAPiul3BRJK22s9klVc4YZgdgYQ==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.40.0"
"data-structure-typed": "^1.41.0"
}
},
"node_modules/babel-jest": {
@ -2927,12 +2927,12 @@
}
},
"node_modules/binary-tree-typed": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.40.0.tgz",
"integrity": "sha512-j459EByswkZFuN4bte7PV8cwwtOFB+37Zwsh2gQJ4k+He/9wSpURaZDXebB4Z4l2Lu+BM/gt4542DEwEykaGaQ==",
"version": "1.41.0",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.41.0.tgz",
"integrity": "sha512-oNHXYVGP2k+qqs1CKt7MFL9araGeFgBhUwIwaE0mj2eHKn2iitirpwt2Umo6j0xXbe2HT685T2POsN8BurXAJw==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.40.0"
"data-structure-typed": "^1.41.0"
}
},
"node_modules/brace-expansion": {
@ -3011,12 +3011,12 @@
}
},
"node_modules/bst-typed": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.40.0.tgz",
"integrity": "sha512-PxM2LtwQOyhytsjtE4dN7XN6GfFHiUfs++jdHVSpkGOqDFNWBM3CYar/nlTjUsTIKzBSSt7BfSIBwo1Lejhwhw==",
"version": "1.41.0",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.41.0.tgz",
"integrity": "sha512-H/MOPuXC53SMo4KleIYFstc3a/GLDVVXShSTG9qrHN2QavZOeg6qyfpkvzOTRyCYjcNlPqMXiwPUtXSaLwH1WA==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.40.0"
"data-structure-typed": "^1.41.0"
}
},
"node_modules/buffer-from": {
@ -3413,9 +3413,9 @@
}
},
"node_modules/data-structure-typed": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.40.0.tgz",
"integrity": "sha512-QW3lgqczAA5pKcjfxVH3+kFUi7vKRbOGcPTuFuhGK756E01GiEcl0WJGf0AXCXmTLbqjvLWGKT7K0qFR9RDPgw==",
"version": "1.41.0",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.41.0.tgz",
"integrity": "sha512-f122SHhf5c0CscW9TFpRmwxQeSemnvAvDG0ZbihA0MDkzTozox47iN3lt2CwjEmWvx73WwOABb1JvmiUZI07og==",
"dev": true
},
"node_modules/debug": {
@ -4771,12 +4771,12 @@
}
},
"node_modules/heap-typed": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.40.0.tgz",
"integrity": "sha512-wEdbSCeI3DpHtCNU4rboi6AEZfxRt1CHRAKG6wtA1+X3aX4IyrGC7lugH06ltrNa0kjZF98r2YFSirFzhWFpkA==",
"version": "1.41.0",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.41.0.tgz",
"integrity": "sha512-ZhEqBuu+T4Vkd0K1xZRNpXWVvF/Uy+bYocZo2ZkgnPJ3gGtqBLmoE7MXEPtZxgH6dfrybVvtBLhAsCIqpjp2Lw==",
"dev": true,
"dependencies": {
"data-structure-typed": "^1.40.0"
"data-structure-typed": "^1.41.0"
}
},
"node_modules/html-escaper": {

View file

@ -1,6 +1,6 @@
{
"name": "data-structure-typed",
"version": "1.41.0",
"version": "1.41.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",
@ -26,16 +26,16 @@
"format:src": "prettier --write 'src/**/*.{js,ts}'",
"format:test": "prettier --write 'test/**/*.{js,ts}'",
"format": "npm run format:src && npm run format:test",
"fix:src": "npm run lint:src && npm run format:src",
"fix:test": "npm run lint:test && npm run format:test",
"fix": "npm run fix:src && npm run fix:test",
"reformat:src": "npm run lint:src && npm run format:src",
"reformat:test": "npm run lint:test && npm run format:test",
"reformat": "npm run reformat:src && npm run reformat:test",
"update:subs": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed --save-dev",
"install:all-subs": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev",
"test": "jest",
"check:deps": "dependency-cruiser src",
"changelog": "auto-changelog",
"coverage:badge": "istanbul-badges-readme",
"ci": "env && git fetch --tags && npm run lint && npm run build && npm run update:subs && npm run test && npm run changelog",
"ci": "env && git fetch --tags && npm run check && npm run lint && npm run build && npm run update:subs && npm run test && npm run changelog",
"copy:to-subs": "sh scripts/copy_to_all_subs.sh",
"publish:subs": "npm run copy:to-subs && sh scripts/publish_all_subs.sh",
"publish:docs": "sh scripts/publish_docs.sh",
@ -61,17 +61,17 @@
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"auto-changelog": "^2.4.0",
"avl-tree-typed": "^1.40.0",
"avl-tree-typed": "^1.41.0",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.40.0",
"bst-typed": "^1.40.0",
"binary-tree-typed": "^1.41.0",
"bst-typed": "^1.41.0",
"dependency-cruiser": "^14.1.0",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"heap-typed": "^1.40.0",
"heap-typed": "^1.41.0",
"istanbul-badges-readme": "^1.8.5",
"jest": "^29.7.0",
"prettier": "^3.0.3",

View file

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

@ -108,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>
{
iterationType: IterationType = IterationType.ITERATIVE;
/**
@ -201,7 +202,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined;
const existNode = key !== undefined ? this.get(key, (node: N) => node.key) : undefined;
const existNode = key !== undefined ? this.getNode(key, (node: N) => node.key) : undefined;
if (this.root) {
if (existNode) {
@ -290,7 +291,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (!this.root) return bstDeletedResult;
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
const curr = this.get(identifier, callback);
const curr = this.getNode(identifier, callback);
if (!curr) return bstDeletedResult;
const parent: N | null = curr?.parent ? curr.parent : null;
@ -342,8 +343,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns the depth of the `distNode` relative to the `beginRoot`.
*/
getDepth(distNode: BTNKey | N | null, beginRoot: BTNKey | N | null = this.root): number {
if (typeof distNode === 'number') distNode = this.get(distNode);
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
if (typeof distNode === 'number') distNode = this.getNode(distNode);
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
let depth = 0;
while (distNode?.parent) {
if (distNode === beginRoot) {
@ -368,7 +369,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns the height of the binary tree.
*/
getHeight(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): number {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
if (!beginRoot) return -1;
if (iterationType === IterationType.RECURSIVE) {
@ -385,7 +386,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) {
@ -604,21 +605,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
}
get<C extends BTNCallback<N, BTNKey>>(
getNode<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
beginRoot?: N,
iterationType?: IterationType
): N | null;
get<C extends BTNCallback<N, N>>(
getNode<C extends BTNCallback<N, N>>(
identifier: N | null,
callback?: C,
beginRoot?: N,
iterationType?: IterationType
): N | null;
get<C extends BTNCallback<N>>(
getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C,
beginRoot?: N,
@ -640,7 +641,7 @@ 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 BTNCallback<N>>(
getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = ((node: N) => node.key) as C,
beginRoot = this.root,
@ -651,6 +652,53 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
}
get<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
beginRoot?: N,
iterationType?: IterationType
): V | undefined;
get<C extends BTNCallback<N, N>>(
identifier: N | null,
callback?: C,
beginRoot?: N,
iterationType?: IterationType
): V | undefined;
get<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C,
beginRoot?: N,
iterationType?: IterationType
): V | undefined;
/**
* The function `get` returns the first node value in a binary tree that matches the given property or key.
* @param {BTNKey | N} identifier - The `identifier` parameter is the key or value of
* the node that you want to find in the binary tree. It can be either a `BTNKey` or `N`
* type.
* @param callback - The `callback` parameter is a function that is used to determine whether a node
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
* whether the node matches the criteria or not. The default callback function
* (`((node: N) => node.key)`) is used if no callback function is
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
* the root node from which the search should begin.
* @param iterationType - The `iterationType` parameter specifies the type of iteration to be
* performed when searching for a node in the binary tree. It can have one of the following values:
* @returns either the found value (of type V) or undefined if no node value is found.
*/
get<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = ((node: N) => node.key) as C,
beginRoot = this.root,
iterationType = this.iterationType
): V | undefined {
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].value ?? undefined;
}
/**
* The function `getPathToRoot` returns an array of nodes starting from a given node and traversing
* up to the root node, with the option to reverse the order of the nodes.
@ -686,7 +734,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* no leftmost node, it returns `null`.
*/
getLeftMost(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): N | null {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
if (!beginRoot) return beginRoot;
@ -812,7 +860,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
beginRoot: BTNKey | N | null = this.root,
iterationType = this.iterationType
): ReturnType<C>[] {
if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot);
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
const ans: ReturnType<BTNCallback<N>>[] = [];
if (!beginRoot) return ans;
@ -888,7 +936,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();
@ -960,7 +1008,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (current.right) queue.push(current.right);
traverse(level + 1);
}
};
traverse(0);
} else {
@ -1055,7 +1103,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `getSuccessor` returns a value of type `N` (the successor node), or `null`
* if there is no successor, or `undefined` if the input `x` is `undefined`.
*/
getSuccessor(x: N): N | null | undefined{
getSuccessor(x: N): N | null | undefined {
if (x.right) {
return this.getLeftMost(x.right);
}
@ -1178,7 +1226,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
* binary tree nodes in a specific order.
*/
* [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
*[Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
if (!node) {
return;
}

View file

@ -19,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.
@ -153,7 +154,9 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return super.addMany(keysOrNodes, data);
}
const inserted: (N | null | undefined)[] = [];
const combinedArr: [BTNKey | N, V][] = keysOrNodes.map((value:(BTNKey | N), index) => [value, data?.[index]] as [BTNKey | N, V]);
const combinedArr: [BTNKey | N, V][] = keysOrNodes.map(
(value: BTNKey | N, index) => [value, data?.[index]] as [BTNKey | N, V]
);
let sorted = [];
function isNodeOrNullTuple(arr: [BTNKey | N, V][]): arr is [N, V][] {
@ -231,7 +234,7 @@ 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 BTNCallback<N>>(
override getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null,
callback: C = ((node: N) => node.key) as C,
beginRoot = this.root,
@ -362,7 +365,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
targetNode: BTNKey | N | null = this.root,
iterationType = this.iterationType
): ReturnType<C>[] {
if (typeof targetNode === 'number') targetNode = this.get(targetNode);
if (typeof targetNode === 'number') targetNode = this.getNode(targetNode);
const ans: ReturnType<BTNCallback<N>>[] = [];
if (!targetNode) return ans;
const targetKey = targetNode.key;

View file

@ -1,27 +1,26 @@
import {RBTNColor} from "../../types";
import {RBTNColor} from '../../types';
export class RBTreeNode {
key: number = 0;
key: number;
parent: RBTreeNode;
left: RBTreeNode;
right: RBTreeNode;
color: number = RBTNColor.BLACK;
constructor() {
constructor(key: number, color: RBTNColor = RBTNColor.BLACK) {
this.key = key;
this.color = color;
this.parent = null as unknown as RBTreeNode;
this.left = null as unknown as RBTreeNode;
this.right = null as unknown as RBTreeNode;
}
}
export const SN = new RBTreeNode(0);
export class RedBlackTree {
constructor() {
this._NIL = new RBTreeNode();
this.NIL.color = RBTNColor.BLACK;
this.NIL.left = null as unknown as RBTreeNode;
this.NIL.right = null as unknown as RBTreeNode;
this._root = this.NIL;
this._root = SN;
}
protected _root: RBTreeNode;
@ -30,12 +29,6 @@ export class RedBlackTree {
return this._root;
}
protected _NIL: RBTreeNode;
get NIL(): RBTreeNode {
return this._NIL;
}
/**
* The `insert` function inserts a new node with a given key into a red-black tree and fixes any
* violations of the red-black tree properties.
@ -44,18 +37,14 @@ export class RedBlackTree {
* @returns The function does not explicitly return anything.
*/
insert(key: number): void {
const node: RBTreeNode = new RBTreeNode();
node.parent = null as unknown as RBTreeNode;
node.key = key;
node.left = this.NIL;
node.right = this.NIL;
node.color = RBTNColor.RED;
const node: RBTreeNode = new RBTreeNode(key, RBTNColor.RED);
node.left = SN;
node.right = SN;
let y: RBTreeNode = null as unknown as RBTreeNode;
let x: RBTreeNode = this.root;
while (x !== this.NIL) {
while (x !== SN) {
y = x;
if (node.key < x.key) {
x = x.left;
@ -94,10 +83,9 @@ export class RedBlackTree {
*/
delete(key: number): void {
const helper = (node: RBTreeNode): void => {
let z: RBTreeNode = this.NIL;
let z: RBTreeNode = SN;
let x: RBTreeNode, y: RBTreeNode;
while (node !== this.NIL) {
while (node !== SN) {
if (node.key === key) {
z = node;
}
@ -109,16 +97,16 @@ export class RedBlackTree {
}
}
if (z === this.NIL) {
if (z === SN) {
return;
}
y = z;
let yOriginalColor: number = y.color;
if (z.left === this.NIL) {
if (z.left === SN) {
x = z.right;
this._rbTransplant(z, z.right);
} else if (z.right === this.NIL) {
} else if (z.right === SN) {
x = z.left;
this._rbTransplant(z, z.left);
} else {
@ -138,13 +126,17 @@ export class RedBlackTree {
y.left.parent = y;
y.color = z.color;
}
if (yOriginalColor === 0) {
if (yOriginalColor === RBTNColor.BLACK) {
this._fixDelete(x);
}
}
};
helper(this.root);
}
isRealNode(node: RBTreeNode): node is RBTreeNode {
return node !== SN && node !== null;
}
/**
* The function `getNode` is a recursive depth-first search algorithm that searches for a node with a
* given key in a red-black tree.
@ -157,40 +149,40 @@ export class RedBlackTree {
*/
getNode(key: number, beginRoot = this.root): RBTreeNode {
const dfs = (node: RBTreeNode): RBTreeNode => {
if (node === this.NIL || key === node.key) {
return node;
}
if (this.isRealNode(node)) {
if (key === node.key) {
return node;
}
if (key < node.key) {
return dfs(node.left);
if (key < node.key) return dfs(node.left);
return dfs(node.right);
} else {
return null as unknown as RBTreeNode;
}
return dfs(node.right);
}
};
return dfs(beginRoot);
}
/**
* The function returns the leftmost node in a red-black tree.
* @param {RBTreeNode} node - The parameter "node" is of type RBTreeNode, which represents a node in
* a Red-Black Tree.
* @returns The leftmost node in the given RBTreeNode.
*/
getLeftMost(node: RBTreeNode): RBTreeNode {
while (node.left !== null && node.left !== this.NIL) {
getLeftMost(node: RBTreeNode = this.root): RBTreeNode {
while (node.left !== null && node.left !== SN) {
node = node.left;
}
return node;
}
/**
* The function returns the rightmost node in a red-black tree.
* @param {RBTreeNode} node - The parameter "node" is of type RBTreeNode.
* @returns the rightmost node in a red-black tree.
*/
getRightMost(node: RBTreeNode): RBTreeNode {
while (node.right !== null && node.right !== this.NIL) {
while (node.right !== null && node.right !== SN) {
node = node.right;
}
return node;
@ -202,13 +194,12 @@ export class RedBlackTree {
* @returns the successor of the given RBTreeNode.
*/
getSuccessor(x: RBTreeNode): RBTreeNode {
if (x.right !== this.NIL) {
if (x.right !== SN) {
return this.getLeftMost(x.right);
}
let y: RBTreeNode = x.parent;
while (y !== this.NIL && y !== null && x === y.right) {
while (y !== SN && y !== null && x === y.right) {
x = y;
y = y.parent;
}
@ -222,13 +213,12 @@ export class RedBlackTree {
* @returns the predecessor of the given RBTreeNode 'x'.
*/
getPredecessor(x: RBTreeNode): RBTreeNode {
if (x.left !== this.NIL) {
if (x.left !== SN) {
return this.getRightMost(x.left);
}
let y: RBTreeNode = x.parent;
while (y !== this.NIL && x === y.left) {
while (y !== SN && x === y.left) {
x = y;
y = y.parent;
}
@ -243,7 +233,7 @@ export class RedBlackTree {
protected _leftRotate(x: RBTreeNode): void {
const y: RBTreeNode = x.right;
x.right = y.left;
if (y.left !== this.NIL) {
if (y.left !== SN) {
y.left.parent = x;
}
y.parent = x.parent;
@ -266,7 +256,7 @@ export class RedBlackTree {
protected _rightRotate(x: RBTreeNode): void {
const y: RBTreeNode = x.left;
x.left = y.right;
if (y.right !== this.NIL) {
if (y.right !== SN) {
y.right.parent = x;
}
y.parent = x.parent;
@ -288,24 +278,21 @@ export class RedBlackTree {
*/
protected _fixDelete(x: RBTreeNode): void {
let s: RBTreeNode;
while (x !== this.root && x.color === 0) {
while (x !== this.root && x.color === RBTNColor.BLACK) {
if (x === x.parent.left) {
s = x.parent.right;
if (s.color === 1) {
s.color = RBTNColor.BLACK;
x.parent.color = RBTNColor.RED;
this._leftRotate(x.parent);
s = x.parent.right;
}
if (s.left.color === 0 && s.right.color === 0) {
if (s.left !== null && s.left.color === RBTNColor.BLACK && s.right.color === RBTNColor.BLACK) {
s.color = RBTNColor.RED;
x = x.parent;
} else {
if (s.right.color === 0) {
if (s.right.color === RBTNColor.BLACK) {
s.left.color = RBTNColor.BLACK;
s.color = RBTNColor.RED;
this._rightRotate(s);
@ -321,20 +308,17 @@ export class RedBlackTree {
} else {
s = x.parent.left;
if (s.color === 1) {
s.color = RBTNColor.BLACK;
x.parent.color = RBTNColor.RED;
this._rightRotate(x.parent);
s = x.parent.left;
}
if (s.right.color === 0 && s.right.color === 0) {
if (s.right.color === RBTNColor.BLACK && s.right.color === RBTNColor.BLACK) {
s.color = RBTNColor.RED;
x = x.parent;
} else {
if (s.left.color === 0) {
if (s.left.color === RBTNColor.BLACK) {
s.right.color = RBTNColor.BLACK;
s.color = RBTNColor.RED;
this._leftRotate(s);
@ -379,14 +363,12 @@ export class RedBlackTree {
if (k.parent === k.parent.parent.right) {
u = k.parent.parent.left;
if (u.color === 1) {
u.color = RBTNColor.BLACK;
k.parent.color = RBTNColor.BLACK;
k.parent.parent.color = RBTNColor.RED;
k = k.parent.parent;
} else {
if (k === k.parent.left) {
k = k.parent;
this._rightRotate(k);
}
@ -399,14 +381,12 @@ export class RedBlackTree {
u = k.parent.parent.right;
if (u.color === 1) {
u.color = RBTNColor.BLACK;
k.parent.color = RBTNColor.BLACK;
k.parent.parent.color = RBTNColor.RED;
k = k.parent.parent;
} else {
if (k === k.parent.right) {
k = k.parent;
this._leftRotate(k);
}
@ -422,4 +402,4 @@ export class RedBlackTree {
}
this.root.color = RBTNColor.BLACK;
}
}
}

View file

@ -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.
@ -169,7 +170,7 @@ export class TreeMultiset<V = any, N extends TreeMultisetNode<V, N> = TreeMultis
} else if (parent.right === undefined) {
parent.right = newNode;
if (newNode !== null) {
this._size = (this.size + 1);
this._size = this.size + 1;
this._setCount(this.count + newNode.count);
}
return parent.right;
@ -282,7 +283,7 @@ export class TreeMultiset<V = any, N extends TreeMultisetNode<V, N> = TreeMultis
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
if (!this.root) return bstDeletedResult;
const curr: N | null = this.get(identifier, callback);
const curr: N | null = this.getNode(identifier, callback);
if (!curr) return bstDeletedResult;
const parent: N | null = curr?.parent ? curr.parent : null;

View file

@ -26,7 +26,6 @@ export abstract class AbstractVertex<V = any> {
this.key = key;
this.value = value;
}
}
export abstract class AbstractEdge<E = any> {
@ -65,7 +64,8 @@ export abstract class AbstractGraph<
E = any,
VO extends AbstractVertex<V> = AbstractVertex<V>,
EO extends AbstractEdge<E> = AbstractEdge<E>
> implements IGraph<V, E, VO, EO> {
> implements IGraph<V, E, VO, EO>
{
protected _vertices: Map<VertexKey, VO> = new Map<VertexKey, VO>();
get vertices(): Map<VertexKey, VO> {
@ -513,14 +513,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);
@ -582,7 +582,7 @@ export abstract class AbstractGraph<
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
}
const heap = new PriorityQueue<{ key: number; value: VO }>({comparator: (a, b) => a.key - b.key});
const heap = new PriorityQueue<{key: number; value: VO}>({comparator: (a, b) => a.key - b.key});
heap.add({key: 0, value: srcVertex});
distMap.set(srcVertex, 0);
@ -811,7 +811,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: (VO | null)[][] } {
floyd(): {costs: number[][]; predecessor: (VO | null)[][]} {
const idAndVertices = [...this._vertices];
const n = idAndVertices.length;
@ -996,5 +996,4 @@ export abstract class AbstractGraph<
protected _getVertexKey(vertexOrKey: VO | VertexKey): VertexKey {
return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
}
}

View file

@ -46,13 +46,14 @@ export class DirectedEdge<E = any> extends AbstractEdge<E> {
}
export class DirectedGraph<
V = any,
E = any,
VO extends DirectedVertex<V> = DirectedVertex<V>,
EO extends DirectedEdge<E> = DirectedEdge<E>
>
V = any,
E = any,
VO extends DirectedVertex<V> = DirectedVertex<V>,
EO extends DirectedEdge<E> = DirectedEdge<E>
>
extends AbstractGraph<V, E, VO, EO>
implements IGraph<V, E, VO, EO> {
implements IGraph<V, E, VO, EO>
{
/**
* The constructor function initializes an instance of a class.
*/

View file

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

View file

@ -133,7 +133,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

@ -8,7 +8,7 @@
import type {Comparator, DFSOrderPattern} from '../../types';
export class Heap<E = any> {
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;
@ -48,7 +48,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

@ -594,7 +594,7 @@ export class DoublyLinkedList<E = any> {
/**
* The function returns an iterator that iterates over the values of a linked list.
*/
* [Symbol.iterator]() {
*[Symbol.iterator]() {
let current = this.head;
while (current) {

View file

@ -565,7 +565,7 @@ export class SinglyLinkedList<E = any> {
/**
* The function returns an iterator that iterates over the values of a linked list.
*/
* [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

@ -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.

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;
}
protected _nodes: { [key: number]: E } = {};
protected _nodes: {[key: number]: E} = {};
get nodes(): { [p: number]: E } {
get nodes(): {[p: number]: E} {
return this._nodes;
}

View file

@ -201,7 +201,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,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,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

@ -7,18 +7,18 @@ describe('AVL Tree Test', () => {
for (const i of arr) tree.add(i, i);
const node6 = tree.get(6);
const node6 = tree.getNode(6);
expect(node6 && tree.getHeight(node6)).toBe(3);
expect(node6 && tree.getDepth(node6)).toBe(1);
const getNodeById = tree.get(10);
const getNodeById = tree.getNode(10);
expect(getNodeById?.key).toBe(10);
const getMinNodeByRoot = tree.getLeftMost();
expect(getMinNodeByRoot?.key).toBe(1);
const node15 = tree.get(15);
const node15 = tree.getNode(15);
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15);
expect(getMinNodeBySpecificNode?.key).toBe(12);
@ -116,18 +116,18 @@ describe('AVL Tree Test recursively', () => {
for (const i of arr) tree.add(i, i);
const node6 = tree.get(6);
const node6 = tree.getNode(6);
expect(node6 && tree.getHeight(node6)).toBe(3);
expect(node6 && tree.getDepth(node6)).toBe(1);
const getNodeById = tree.get(10);
const getNodeById = tree.getNode(10);
expect(getNodeById?.key).toBe(10);
const getMinNodeByRoot = tree.getLeftMost();
expect(getMinNodeByRoot?.key).toBe(1);
const node15 = tree.get(15);
const node15 = tree.getNode(15);
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15);
expect(getMinNodeBySpecificNode?.key).toBe(12);

View file

@ -107,7 +107,7 @@ describe('BinaryTree', () => {
expect(tree.has(2)).toBe(true);
expect(tree.has(3)).toBe(true);
expect(tree.has(4)).toBe(false);
const node4 = tree.get(4);
const node4 = tree.getNode(4);
expect(tree.has(node4)).toBe(false);
expect(tree.has(node4, node => node)).toBe(false);
expect(tree.has('3', node => node.value?.toString())).toBe(true);
@ -169,13 +169,13 @@ describe('BinaryTree', () => {
new BinaryTreeNode(4, 4)
]);
expect(tree.isSubtreeBST(tree.get(4), IterationType.RECURSIVE)).toBe(true);
expect(tree.isSubtreeBST(tree.get(4), IterationType.ITERATIVE)).toBe(true);
expect(tree.isSubtreeBST(tree.getNode(4), IterationType.RECURSIVE)).toBe(true);
expect(tree.isSubtreeBST(tree.getNode(4), IterationType.ITERATIVE)).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]);
expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]);
});
it('should clear the tree', () => {
@ -234,9 +234,9 @@ describe('BinaryTree Morris Traversal', () => {
});
it('after morris traversals should the structure of the tree be correct', () => {
const node1 = tree.get(1);
const node2 = tree.get(2);
const node3 = tree.get(3);
const node1 = tree.getNode(1);
const node2 = tree.getNode(2);
const node3 = tree.getNode(3);
expect(node1?.left).toBe(node2);
expect(node1?.right).toBe(node3);
});
@ -339,8 +339,8 @@ describe('BinaryTree', () => {
tree.add(3, 'B');
tree.add(7, 'C');
const nodeA = tree.get(5);
const nodeB = tree.get(3);
const nodeA = tree.getNode(5);
const nodeB = tree.getNode(3);
expect(nodeA?.key).toBe(5);
expect(nodeA?.value).toBe('A');
@ -351,7 +351,7 @@ describe('BinaryTree', () => {
it('should return null when getting a non-existent node', () => {
tree.add(5, 'A');
const node = tree.get(3);
const node = tree.getNode(3);
expect(node).toBe(null);
});
@ -421,7 +421,7 @@ describe('BinaryTree', () => {
tree.delete(3);
expect(tree.size).toBe(2);
expect(tree.get(3)).toBe(null);
expect(tree.getNode(3)).toBe(null);
});
it('should check if the tree is perfectly balanced', () => {

View file

@ -19,20 +19,20 @@ describe('BST operations test', () => {
expect(bst.has(6)).toBe(true);
const node6 = bst.get(6);
const node6 = bst.getNode(6);
expect(node6 && bst.getHeight(6)).toBe(2);
expect(node6 && bst.getDepth(6)).toBe(3);
const nodeId10 = bst.get(10);
const nodeId10 = bst.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.get(9, node => node.value);
const nodeVal9 = bst.getNode(9, node => node.value);
expect(nodeVal9?.key).toBe(9);
const leftMost = bst.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = bst.get(15);
const node15 = bst.getNode(15);
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
@ -46,7 +46,7 @@ describe('BST operations test', () => {
expect(node15).toBeInstanceOf(BSTNode);
const node11 = bst.get(11);
const node11 = bst.getNode(11);
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = bst.dfs(node => node, 'in');
@ -222,20 +222,20 @@ describe('BST operations test', () => {
expect(objBST.has(6)).toBe(true);
const node6 = objBST.get(6);
const node6 = objBST.getNode(6);
expect(node6 && objBST.getHeight(node6)).toBe(2);
expect(node6 && objBST.getDepth(node6)).toBe(3);
const nodeId10 = objBST.get(10);
const nodeId10 = objBST.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = objBST.get(9);
const nodeVal9 = objBST.getNode(9);
expect(nodeVal9?.key).toBe(9);
const leftMost = objBST.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = objBST.get(15);
const node15 = objBST.getNode(15);
expect(node15?.value).toEqual({key: 15, keyA: 15});
const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
@ -250,7 +250,7 @@ describe('BST operations test', () => {
expect(node15).toBeInstanceOf(BSTNode);
const node11 = objBST.get(11);
const node11 = objBST.getNode(11);
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = objBST.dfs(node => node, 'in');
@ -409,20 +409,21 @@ describe('BST operations test recursively', () => {
expect(bst.has(6)).toBe(true);
const node6 = bst.get(6);
const node6 = bst.getNode(6);
expect(node6 && bst.getHeight(6)).toBe(2);
expect(node6 && bst.getDepth(6)).toBe(3);
const nodeId10 = bst.get(10);
const nodeId10 = bst.getNode(10);
expect(bst.get(10)).toBe(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.get(9, node => node.value);
const nodeVal9 = bst.getNode(9, node => node.value);
expect(nodeVal9?.key).toBe(9);
const leftMost = bst.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = bst.get(15);
const node15 = bst.getNode(15);
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
@ -436,7 +437,7 @@ describe('BST operations test recursively', () => {
expect(node15).toBeInstanceOf(BSTNode);
const node11 = bst.get(11);
const node11 = bst.getNode(11);
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = bst.dfs(node => node, 'in');
@ -612,20 +613,21 @@ describe('BST operations test recursively', () => {
expect(objBST.has(6)).toBe(true);
const node6 = objBST.get(6);
const node6 = objBST.getNode(6);
expect(objBST.get(6)).toEqual({key: 6, keyA: 6});
expect(node6 && objBST.getHeight(node6)).toBe(2);
expect(node6 && objBST.getDepth(node6)).toBe(3);
const nodeId10 = objBST.get(10);
const nodeId10 = objBST.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = objBST.get(9);
const nodeVal9 = objBST.getNode(9);
expect(nodeVal9?.key).toBe(9);
const leftMost = objBST.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = objBST.get(15);
const node15 = objBST.getNode(15);
expect(node15?.value).toEqual({key: 15, keyA: 15});
const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
@ -640,7 +642,7 @@ describe('BST operations test recursively', () => {
expect(node15).toBeInstanceOf(BSTNode);
const node11 = objBST.get(11);
const node11 = objBST.getNode(11);
expect(node11).toBeInstanceOf(BSTNode);
const dfsInorderNodes = objBST.dfs(node => node, 'in');

View file

@ -20,8 +20,8 @@ describe('Overall BinaryTree Test', () => {
leftMost?.key === 1; // true
expect(leftMost?.key).toBe(1);
bst.delete(6);
bst.get(6); // null
expect(bst.get(6)).toBeNull();
bst.getNode(6); // null
expect(bst.getNode(6)).toBeNull();
bst.isAVLBalanced(); // true or false
expect(bst.isAVLBalanced()).toBe(true);
const bfsIDs: number[] = [];

View file

@ -1,5 +1,5 @@
import { RedBlackTree, RBTreeNode } from '../../../../src';
import {getRandomInt} from "../../../utils";
import {RBTreeNode, RedBlackTree, SN} from '../../../../src';
import {getRandomInt} from '../../../utils';
describe('RedBlackTree', () => {
let tree: RedBlackTree;
@ -17,7 +17,7 @@ describe('RedBlackTree', () => {
expect(tree.getNode(10)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(20)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(5)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(15)).toBe(tree.NIL);
expect(tree.getNode(15)).toBe(null);
});
test('should insert and find nodes with negative keys', () => {
@ -36,7 +36,7 @@ describe('RedBlackTree', () => {
tree.insert(5);
tree.delete(20);
expect(tree.getNode(20)).toBe(tree.NIL);
expect(tree.getNode(20)).toBe(null);
});
test('should handle deleting a non-existent node', () => {
@ -45,7 +45,7 @@ describe('RedBlackTree', () => {
tree.insert(5);
tree.delete(15);
expect(tree.getNode(15)).toBe(tree.NIL);
expect(tree.getNode(15)).toBe(null);
});
});
@ -63,7 +63,7 @@ describe('RedBlackTree', () => {
test('should handle an empty tree', () => {
const minNode = tree.getLeftMost(tree.root);
expect(minNode).toBe(tree.NIL);
expect(minNode).toBe(SN);
});
});
@ -81,7 +81,7 @@ describe('RedBlackTree', () => {
test('should handle an empty tree', () => {
const maxNode = tree.getRightMost(tree.root);
expect(maxNode).toBe(tree.NIL);
expect(maxNode).toBe(SN);
});
});
@ -105,7 +105,7 @@ describe('RedBlackTree', () => {
const node = tree.getNode(10);
const successorNode = tree.getSuccessor(node);
// TODO not sure if it should be null or tree.NIL
// TODO not sure if it should be null or SN
expect(successorNode).toBe(null);
});
});
@ -130,13 +130,12 @@ describe('RedBlackTree', () => {
const node = tree.getNode(20);
const predecessorNode = tree.getPredecessor(node);
// TODO not sure if it should be tree.NIL or something else.
// TODO not sure if it should be SN or something else.
expect(predecessorNode).toBe(tree.getNode(10));
});
});
});
describe('RedBlackTree', () => {
let tree: RedBlackTree;
@ -158,7 +157,7 @@ describe('RedBlackTree', () => {
tree.insert(20);
tree.insert(5);
tree.delete(20);
expect(tree.getNode(20)).toBe(tree.NIL);
expect(tree.getNode(20)).toBe(null);
});
it('should get the successor of a node', () => {
@ -210,14 +209,15 @@ describe('RedBlackTree', () => {
});
it('should fix the tree after insertion', () => {
for (let i = 0; i < 1000; i++) {
tree.insert(getRandomInt(-100, 1000));
tree.delete(getRandomInt(-100, 1000));
}
tree.insert(1);
tree.insert(2);
tree.insert(5);
tree.insert(15);
const node15F = tree.getNode(15);
expect(node15F.left).toBe(SN);
expect(node15F.right).toBe(SN);
expect(node15F.parent).toBe(tree.getNode(5));
tree.insert(25);
tree.insert(10);
tree.insert(8);
@ -229,14 +229,50 @@ describe('RedBlackTree', () => {
tree.insert(50);
tree.insert(155);
tree.insert(225);
const node225F = tree.getNode(225);
expect(node225F.left).toBe(SN);
expect(node225F.right).toBe(SN);
expect(node225F.parent.key).toBe(155);
tree.insert(7);
const node15S = tree.getNode(15);
expect(node15S.left.key).toBe(8);
expect(node15S.right.key).toBe(28);
expect(node15S).toBe(tree.root);
expect(node15S.parent).toBe(null);
tree.delete(15);
expect(tree.root.key).toBe(22);
expect(tree.root.parent).toBe(null);
const node15T = tree.getNode(15);
expect(node15T).toBe(null);
tree.insert(23);
tree.insert(33);
tree.insert(15);
const nodeLM = tree.getLeftMost();
expect(nodeLM.key).toBe(1);
// Verify that the tree is still a valid Red-Black Tree
// You can add assertions to check the Red-Black Tree properties
const node50 = tree.getNode(50);
expect(node50.key).toBe(50);
expect(node50.left.key).toBe(33);
expect(node50.right).toBe(SN);
const node15Fo = tree.getNode(15);
expect(node15Fo.key).toBe(15);
expect(node15Fo.left).toBe(SN);
const node225S = tree.getNode(225);
expect(node225S.left).toBe(SN);
expect(node225S.right).toBe(SN);
expect(node225S.parent.key).toBe(155);
expect(tree.getNode(0)).toBe(null);
});
it('should fix the tree after insertion and deletion', () => {
for (let i = 0; i < 1000; i++) {
tree.insert(getRandomInt(-100, 1000));
tree.delete(getRandomInt(-100, 1000));
}
});
});

View file

@ -23,10 +23,10 @@ describe('TreeMultiset operations test', () => {
expect(treeMultiset.getHeight(6)).toBe(3);
expect(treeMultiset.getDepth(6)).toBe(1);
const nodeId10 = treeMultiset.get(10);
const nodeId10 = treeMultiset.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultiset.get(9, node => node.value);
const nodeVal9 = treeMultiset.getNode(9, node => node.value);
expect(nodeVal9?.key).toBe(9);
const nodesByCount1 = treeMultiset.getNodes(1, node => node.count);
@ -37,7 +37,7 @@ describe('TreeMultiset operations test', () => {
const leftMost = treeMultiset.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = treeMultiset.get(15);
const node15 = treeMultiset.getNode(15);
const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
@ -53,7 +53,7 @@ describe('TreeMultiset operations test', () => {
const subTreeAdd = treeMultiset.subTreeTraverse((node: TreeMultisetNode<number>) => (node.count += 1), 15);
expect(subTreeAdd);
}
const node11 = treeMultiset.get(11);
const node11 = treeMultiset.getNode(11);
expect(node11 instanceof TreeMultisetNode);
if (node11 instanceof TreeMultisetNode) {
const allGreaterNodesAdded = treeMultiset.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11);
@ -263,10 +263,10 @@ describe('TreeMultiset operations test recursively', () => {
expect(treeMultiset.getHeight(6)).toBe(3);
expect(treeMultiset.getDepth(6)).toBe(1);
const nodeId10 = treeMultiset.get(10);
const nodeId10 = treeMultiset.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultiset.get(9, node => node.value);
const nodeVal9 = treeMultiset.getNode(9, node => node.value);
expect(nodeVal9?.key).toBe(9);
const nodesByCount1 = treeMultiset.getNodes(1, node => node.count);
@ -277,7 +277,7 @@ describe('TreeMultiset operations test recursively', () => {
const leftMost = treeMultiset.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = treeMultiset.get(15);
const node15 = treeMultiset.getNode(15);
const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
@ -293,7 +293,7 @@ describe('TreeMultiset operations test recursively', () => {
const subTreeAdd = treeMultiset.subTreeTraverse((node: TreeMultisetNode<number>) => (node.count += 1), 15);
expect(subTreeAdd);
}
const node11 = treeMultiset.get(11);
const node11 = treeMultiset.getNode(11);
expect(node11 instanceof TreeMultisetNode);
if (node11 instanceof TreeMultisetNode) {
const allGreaterNodesAdded = treeMultiset.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11);

View file

@ -23,9 +23,11 @@ exports.bigO = {
CUBED: Math.pow(exports.magnitude.SQUARED, 3) / 1000,
FACTORIAL: 10000
};
function findPotentialN(input) {
var longestArray = [];
var mostProperties = {};
function recurse(obj) {
if (Array.isArray(obj)) {
if (obj.length > longestArray.length) {
@ -41,6 +43,7 @@ function findPotentialN(input) {
});
}
}
if (Array.isArray(input)) {
input.forEach(function (item) {
recurse(item);
@ -51,6 +54,7 @@ function findPotentialN(input) {
// return [longestArray, mostProperties] : [any[], { [key: string]: any }];
return Math.max(longestArray.length, Object.keys(mostProperties).length);
}
function linearRegression(x, y) {
var n = x.length;
var sumX = x.reduce(function (acc, val) {
@ -87,6 +91,7 @@ function linearRegression(x, y) {
var rSquared = 1 - totalVariation / explainedVariation;
return {slope: slope, intercept: intercept, rSquared: rSquared};
}
function estimateBigO(runtimes, dataSizes) {
// Make sure the input runtimes and data sizes have the same length
if (runtimes.length !== dataSizes.length) {
@ -137,7 +142,9 @@ function estimateBigO(runtimes, dataSizes) {
return complexities.join(' or ');
}
}
var methodLogs = new Map();
function logBigOMetricsWrap(fn, args, fnName) {
var startTime = performance.now();
var result = fn(args);
@ -169,7 +176,9 @@ function logBigOMetricsWrap(fn, args, fnName) {
}
return result;
}
exports.logBigOMetricsWrap = logBigOMetricsWrap;
function logBigOMetrics(target, propertyKey, descriptor) {
var originalMethod = descriptor.value;
descriptor.value = function () {
@ -209,4 +218,5 @@ function logBigOMetrics(target, propertyKey, descriptor) {
};
return descriptor;
}
exports.logBigOMetrics = logBigOMetrics;