Compare commits

..

5 commits

12 changed files with 165 additions and 121 deletions

48
package-lock.json generated
View file

@ -19,11 +19,11 @@
"@typescript-eslint/eslint-plugin": "^8.12.1",
"@typescript-eslint/parser": "^8.12.1",
"auto-changelog": "^2.5.0",
"avl-tree-typed": "^1.52.6",
"avl-tree-typed": "^1.52.8",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.52.6",
"bst-typed": "^1.52.6",
"data-structure-typed": "^1.52.7",
"binary-tree-typed": "^1.52.8",
"bst-typed": "^1.52.8",
"data-structure-typed": "^1.52.8",
"dependency-cruiser": "^16.5.0",
"doctoc": "^2.2.1",
"eslint": "^9.13.0",
@ -32,7 +32,7 @@
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"fast-glob": "^3.3.2",
"heap-typed": "^1.52.6",
"heap-typed": "^1.52.8",
"istanbul-badges-readme": "^1.9.0",
"jest": "^29.7.0",
"js-sdsl": "^4.4.2",
@ -3437,13 +3437,13 @@
}
},
"node_modules/avl-tree-typed": {
"version": "1.52.6",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.52.6.tgz",
"integrity": "sha512-OywUuitOuCxBJI0u2qkymYWXwSl/EC+ysY/rQtyaNFwiRzkx1vSjqz/woQcQnIbxKRANz00FqIlDpfaZlwMHRA==",
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.52.8.tgz",
"integrity": "sha512-8oU+KjIVtzF9U12NudYuQNBX/If1DL1bKrbqLtKk5RjEq1Jsl56/GIvuzbvKHnGgv9h7DpXHyJUCLjAz3zjhbg==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.6"
"data-structure-typed": "^1.52.8"
}
},
"node_modules/babel-jest": {
@ -3602,13 +3602,13 @@
}
},
"node_modules/binary-tree-typed": {
"version": "1.52.6",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.52.6.tgz",
"integrity": "sha512-fhXJhIjjeYDmNEB+smugaCHHdZkuPCjxzfg/gAkTdF3cYGVKqRan42h2AT0IOFHeAwB1TMNoxqy0blso6rbe+Q==",
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.52.8.tgz",
"integrity": "sha512-tjUcMufU41Tmp+/6/cBHdSonA+gjhMUpfJqspJ06xp8A3gfWQpf9TjHdY9FxpeeTLPnREpU4SGGZqqIk372XVA==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.6"
"data-structure-typed": "^1.52.8"
}
},
"node_modules/brace-expansion": {
@ -3691,13 +3691,13 @@
}
},
"node_modules/bst-typed": {
"version": "1.52.6",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.52.6.tgz",
"integrity": "sha512-zqoh+BtWpqHyAp3Au61ukMMZ59qn2brh5oIKFFf92BNhCIMZDlV/Q0f4cWzkLa7CcFWqVo6VqpOsVICvTZzDKg==",
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.52.8.tgz",
"integrity": "sha512-YMRUaz8jNxSymvKNNyeJR8HozHRgDWUw8PO0QLSvaW/c4Ed/KhpDSyBth52NClFnbJnNV2lTsd01k/VwuerimA==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.6"
"data-structure-typed": "^1.52.8"
}
},
"node_modules/buffer-from": {
@ -4069,9 +4069,9 @@
}
},
"node_modules/data-structure-typed": {
"version": "1.52.7",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.52.7.tgz",
"integrity": "sha512-j5ckg8Um4PfYD/GM6QJZ0Y28rgatecVADPRXgkETq0RqALPt8296om7lTKmw9VXNn6a2xs+7q6YlmTfS82h2Gw==",
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.52.8.tgz",
"integrity": "sha512-2YNk0YSjwK0IA8b+g68bmbWtc82M4IzIqo/VUSY16lO3LZ+AajxPkBK68VHPP07ckNNLhdLbh04RoQd3dMNNiw==",
"dev": true,
"license": "MIT"
},
@ -5946,13 +5946,13 @@
}
},
"node_modules/heap-typed": {
"version": "1.52.6",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.52.6.tgz",
"integrity": "sha512-uIUQkPXPnHFYm9uFECxhaIWlZ0WPikxDkfnYYEg7630FpYfWsl/Z98T26/2/7nAD/iTOZhHd02KajgnzeIU6WA==",
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.52.8.tgz",
"integrity": "sha512-Zzq+V9IQMf8o2FrIeqc0kRxRyDxOyUPX5dXRi095LnpOFRzUXZoSl2hggbHfsjKEaKwLDRoJuS9t77alqmK4NQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.6"
"data-structure-typed": "^1.52.8"
}
},
"node_modules/html-escaper": {

View file

@ -68,11 +68,11 @@
"@typescript-eslint/eslint-plugin": "^8.12.1",
"@typescript-eslint/parser": "^8.12.1",
"auto-changelog": "^2.5.0",
"avl-tree-typed": "^1.52.6",
"avl-tree-typed": "^1.52.8",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.52.6",
"bst-typed": "^1.52.6",
"data-structure-typed": "^1.52.7",
"binary-tree-typed": "^1.52.8",
"bst-typed": "^1.52.8",
"data-structure-typed": "^1.52.8",
"dependency-cruiser": "^16.5.0",
"doctoc": "^2.2.1",
"eslint": "^9.13.0",
@ -81,7 +81,7 @@
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"fast-glob": "^3.3.2",
"heap-typed": "^1.52.6",
"heap-typed": "^1.52.8",
"istanbul-badges-readme": "^1.9.0",
"jest": "^29.7.0",
"js-sdsl": "^4.4.2",

View file

@ -232,9 +232,9 @@ export class AVLTreeMultiMap<
*
* The function overrides the delete method in a binary tree data structure, handling deletion of
* nodes and maintaining balance in the tree.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>} predicate - The `predicate`
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `predicate`
* parameter in the `delete` method is used to specify the condition for deleting a node from the
* binary tree. It can be a key, node, entry, or a custom predicate function that determines which
* binary tree. It can be a key, node, or entry that determines which
* node(s) should be deleted.
* @param [ignoreCount=false] - The `ignoreCount` parameter in the `override delete` method is a
* boolean flag that determines whether to ignore the count of the node being deleted. If
@ -246,13 +246,13 @@ export class AVLTreeMultiMap<
* deleted node and whether balancing is needed in the tree.
*/
override delete(
predicate: BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>,
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
ignoreCount = false
): BinaryTreeDeleteResult<NODE>[] {
const deletedResult: BinaryTreeDeleteResult<NODE>[] = [];
if (!this.root) return deletedResult;
const curr: NODE | undefined = this.getNode(predicate) ?? undefined;
const curr: NODE | undefined = this.getNode(keyOrNodeOrEntryOrRaw) ?? undefined;
if (!curr) return deletedResult;
const parent: NODE | undefined = curr?.parent ? curr.parent : undefined;

View file

@ -160,15 +160,15 @@ export class AVLTree<
*
* The function overrides the delete method in a TypeScript class, performs deletion, and then
* balances the tree if necessary.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>} predicate - The `predicate`
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `keyOrNodeOrEntryOrRaw`
* parameter in the `override delete` method can be one of the following types:
* @returns The `delete` method is being overridden in this code snippet. It first calls the `delete`
* method from the superclass (presumably a parent class) with the provided `predicate`, which could
* be a key, node, entry, or a custom predicate. The result of this deletion operation is stored in
* `deletedResults`, which is an array of `BinaryTreeDeleteResult` objects.
*/
override delete(predicate: BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>): BinaryTreeDeleteResult<NODE>[] {
const deletedResults = super.delete(predicate);
override delete(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): BinaryTreeDeleteResult<NODE>[] {
const deletedResults = super.delete(keyOrNodeOrEntryOrRaw);
for (const { needBalanced } of deletedResults) {
if (needBalanced) {
this._balancePath(needBalanced);

View file

@ -515,22 +515,20 @@ export class BinaryTree<
*
* The function `delete` in TypeScript implements the deletion of a node in a binary tree and returns
* the deleted node along with information for tree balancing.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>} keyOrNodeOrEntryOrRawOrPredicate
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw
* - The `delete` method you provided is used to delete a node from a binary tree based on the key,
* node, entry, raw data, or a custom predicate. The method returns an array of
* node, entry or raw data. The method returns an array of
* `BinaryTreeDeleteResult` objects containing information about the deleted node and whether
* balancing is needed.
* @returns The `delete` method returns an array of `BinaryTreeDeleteResult` objects. Each object in
* the array contains information about the node that was deleted (`deleted`) and the node that may
* need to be balanced (`needBalanced`).
*/
delete(
keyOrNodeOrEntryOrRawOrPredicate: BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>
): BinaryTreeDeleteResult<NODE>[] {
delete(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): BinaryTreeDeleteResult<NODE>[] {
const deletedResult: BinaryTreeDeleteResult<NODE>[] = [];
if (!this._root) return deletedResult;
const curr = this.getNode(keyOrNodeOrEntryOrRawOrPredicate);
const curr = this.getNode(keyOrNodeOrEntryOrRaw);
if (!curr) return deletedResult;
const parent: NODE | undefined = curr?.parent;
@ -1683,20 +1681,14 @@ export class BinaryTree<
beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root,
options?: BinaryTreePrintOptions
): string {
const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
const opts = { isShowUndefined: false, isShowNull: true, isShowRedBlackNIL: false, ...options };
beginRoot = this.ensureNode(beginRoot);
let output = '';
if (!beginRoot) return output;
if (opts.isShowUndefined)
output += `U for undefined
`;
if (opts.isShowNull)
output += `N for null
`;
if (opts.isShowRedBlackNIL)
output += `S for Sentinel Node(NIL)
`;
if (opts.isShowUndefined) output += `U for undefined\n`;
if (opts.isShowNull) output += `N for null\n`;
if (opts.isShowRedBlackNIL) output += `S for Sentinel Node(NIL)\n`;
const display = (root: OptBTNOrNull<NODE>): void => {
const [lines, , ,] = this._displayAux(root, opts);
@ -1711,20 +1703,24 @@ export class BinaryTree<
return output;
}
protected _dfs<C extends BTNCallback<NODE>>(
callback?: C,
pattern?: DFSOrderPattern,
beginRoot?: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
iterationType?: IterationType
): ReturnType<C>[];
protected _dfs<C extends BTNCallback<NODE | null>>(
callback?: C,
pattern?: DFSOrderPattern,
beginRoot?: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
iterationType?: IterationType,
includeNull?: boolean
): ReturnType<C>[];
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
*
* The function `print` in TypeScript overrides the default print behavior to log a visual
* representation of the binary tree to the console.
* @param {BinaryTreePrintOptions} [options] - The `options` parameter is used to specify the
* printing options for the binary tree. It is an optional parameter that allows you to customize how
* the binary tree is printed, such as choosing between different traversal orders or formatting
* options.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} beginRoot - The `beginRoot` parameter in the
* `override print` method is used to specify the starting point for printing the binary tree. It can
* be either a key, a node, an entry, or the root of the tree. If no specific starting point is
* provided, the default value is set to
*/
override print(options?: BinaryTreePrintOptions, beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root) {
console.log(this.toVisual(beginRoot, options));
}
/**
* Time complexity: O(n)

View file

@ -310,28 +310,26 @@ export class BST<
if (!isBalanceAdd) {
for (const kve of keysOrNodesOrEntriesOrRaws) {
const value = valuesIterator?.next().value;
const nn = this.add(kve, value);
inserted.push(nn);
inserted.push(this.add(kve, value));
}
return inserted;
}
const realBTNExemplars: (R | BTNPureKeyOrNodeOrEntry<K, V, NODE>)[] = [];
const isRealBTNExemplar = (
kve: BTNKeyOrNodeOrEntry<K, V, NODE> | R
): kve is BTNPureKeyOrNodeOrEntry<K, V, NODE> => {
if (kve === undefined || kve === null) return false;
return !(this.isEntry(kve) && (kve[0] === undefined || kve[0] === null));
};
const realBTNExemplars: {
key: R | BTNKeyOrNodeOrEntry<K, V, NODE>;
value: V | undefined;
orgIndex: number;
}[] = [];
let i = 0;
for (const kve of keysOrNodesOrEntriesOrRaws) {
if (isRealBTNExemplar(kve)) realBTNExemplars.push(kve);
realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i });
i++;
}
let sorted: (R | BTNPureKeyOrNodeOrEntry<K, V, NODE>)[] = [];
let sorted: { key: R | BTNKeyOrNodeOrEntry<K, V, NODE>; value: V | undefined; orgIndex: number }[] = [];
sorted = realBTNExemplars.sort((a, b) => {
sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
let keyA: K | undefined | null, keyB: K | undefined | null;
if (this.isEntry(a)) keyA = a[0];
else if (this.isRealNode(a)) keyA = a.key;
@ -355,12 +353,12 @@ export class BST<
return 0;
});
const _dfs = (arr: (R | BTNPureKeyOrNodeOrEntry<K, V, NODE>)[]) => {
const _dfs = (arr: { key: R | BTNKeyOrNodeOrEntry<K, V, NODE>; value: V | undefined; orgIndex: number }[]) => {
if (arr.length === 0) return;
const mid = Math.floor((arr.length - 1) / 2);
const newNode = this.add(arr[mid]);
inserted.push(newNode);
const { key, value, orgIndex } = arr[mid];
inserted[orgIndex] = this.add(key, value);
_dfs(arr.slice(0, mid));
_dfs(arr.slice(mid + 1));
};
@ -374,8 +372,8 @@ export class BST<
const [l, r] = popped;
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const newNode = this.add(sorted[m]);
inserted.push(newNode);
const { key, value, orgIndex } = sorted[m];
inserted[orgIndex] = this.add(key, value);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}

View file

@ -230,7 +230,7 @@ export class RedBlackTree<
*
* The function overrides the delete method in a binary tree data structure to remove a node based on
* a given predicate and maintain the binary search tree properties.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>} predicate - The `predicate`
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `keyOrNodeOrEntryOrRaw`
* parameter in the `override delete` method is used to specify the condition or key based on which a
* node should be deleted from the binary tree. It can be a key, a node, an entry, or a predicate
* function that determines which node(s) should be deleted.
@ -238,13 +238,16 @@ export class RedBlackTree<
* objects. Each object in the array contains information about the deleted node and whether
* balancing is needed.
*/
override delete(predicate: BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>): BinaryTreeDeleteResult<NODE>[] {
if (predicate === null) return [];
override delete(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): BinaryTreeDeleteResult<NODE>[] {
if (keyOrNodeOrEntryOrRaw === null) return [];
const results: BinaryTreeDeleteResult<NODE>[] = [];
let nodeToDelete: OptBSTN<NODE>;
if (this._isPredicated(predicate)) nodeToDelete = this.getNode(predicate);
else nodeToDelete = this.isRealNode(predicate) ? predicate : this.getNode(predicate);
if (this._isPredicated(keyOrNodeOrEntryOrRaw)) nodeToDelete = this.getNode(keyOrNodeOrEntryOrRaw);
else
nodeToDelete = this.isRealNode(keyOrNodeOrEntryOrRaw)
? keyOrNodeOrEntryOrRaw
: this.getNode(keyOrNodeOrEntryOrRaw);
if (!nodeToDelete) {
return results;

View file

@ -232,10 +232,9 @@ export class TreeMultiMap<
*
* The function `delete` in TypeScript overrides the deletion operation in a binary tree data
* structure, handling cases where nodes have children and maintaining balance in the tree.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>} predicate - The `predicate`
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `predicate`
* parameter in the `delete` method is used to specify the condition or key based on which a node
* should be deleted from the binary tree. It can be a key, a node, an entry, or a predicate
* function.
* should be deleted from the binary tree. It can be a key, a node, or an entry.
* @param [ignoreCount=false] - The `ignoreCount` parameter in the `override delete` method is a
* boolean flag that determines whether to ignore the count of nodes when performing deletion. If
* `ignoreCount` is set to `true`, the method will delete the node regardless of its count. If
@ -243,16 +242,19 @@ export class TreeMultiMap<
* @returns The `override delete` method returns an array of `BinaryTreeDeleteResult<NODE>` objects.
*/
override delete(
predicate: BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>,
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
ignoreCount = false
): BinaryTreeDeleteResult<NODE>[] {
if (predicate === null) return [];
if (keyOrNodeOrEntryOrRaw === null) return [];
const results: BinaryTreeDeleteResult<NODE>[] = [];
let nodeToDelete: OptBSTN<NODE>;
if (this._isPredicated(predicate)) nodeToDelete = this.getNode(predicate);
else nodeToDelete = this.isRealNode(predicate) ? predicate : this.getNode(predicate);
if (this._isPredicated(keyOrNodeOrEntryOrRaw)) nodeToDelete = this.getNode(keyOrNodeOrEntryOrRaw);
else
nodeToDelete = this.isRealNode(keyOrNodeOrEntryOrRaw)
? keyOrNodeOrEntryOrRaw
: this.getNode(keyOrNodeOrEntryOrRaw);
if (!nodeToDelete) {
return results;

View file

@ -23,10 +23,10 @@ describe('Individual package BST operations test', () => {
const nodeId10 = bst.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.getNode(9, node => node.value);
const nodeVal9 = bst.getNode(node => node.value === 9);
expect(nodeVal9?.key).toBe(undefined);
const nodeVal11 = bst.getNode(11, node => node.value);
const nodeVal11 = bst.getNode(node => node.value === 11);
expect(nodeVal11?.key).toBe(11);
const leftMost = bst.getLeftMost(node => node);

View file

@ -292,6 +292,26 @@ describe('AVLTree', () => {
// You can add more specific assertions to check the tree's balance and structure.
});
it('should addMany undefined and null', () => {
const avl = new AVLTree<number, string>();
const addManyWithUndefined = avl.addMany([1, undefined, 3]);
expect(addManyWithUndefined).toEqual([true, false, true]);
expect(avl.get(undefined)).toBe(undefined);
const addManyWithNull = avl.addMany([1, null, 3, 4]);
expect(addManyWithNull).toEqual([true, false, true, true]);
const addManyEntriesWithNull = avl.addMany([
[1, '1'],
[null, 'null'],
[3, '3'],
[4, '4']
]);
expect(addManyEntriesWithNull).toEqual([true, false, true, true]);
expect(avl.get(null)).toBe(undefined);
const node0 = avl.add(0, '0');
expect(node0).toBe(true);
expect(avl.get(0)).toBe('0');
});
it('should balance the tree using _balanceLR when nodes are deleted', () => {
const avlTree = new AVLTree();
avlTree.add([10, 'A']);

View file

@ -105,6 +105,27 @@ describe('BinaryTree addMany', () => {
expect(tree.getNodeByKey(4)?.value).toBe(44);
expect(tree.getNodeByKey(1)?.value).toBe(1);
});
it('should addMany undefined and null', () => {
const binaryTree = new BinaryTree<number, string>();
const addManyWithUndefined = binaryTree.addMany([1, undefined, 3]);
expect(addManyWithUndefined).toEqual([true, false, true]);
expect(binaryTree.get(undefined)).toBe(undefined);
const addManyWithNull = binaryTree.addMany([1, null, 3, 4]);
expect(addManyWithNull).toEqual([true, true, true, true]);
const addManyEntriesWithNull = binaryTree.addMany([
[1, '1'],
[null, 'null'],
[3, '3'],
[4, '4']
]);
expect(addManyEntriesWithNull).toEqual([true, true, true, true]);
expect(binaryTree.get(null)).toBe(undefined);
expect(binaryTree.getNode(null)).toBe(null);
const node0 = binaryTree.add(0, '0');
expect(node0).toBe(true);
expect(binaryTree.get(0)).toBe('0');
});
});
describe('BinaryTree', () => {
@ -298,27 +319,26 @@ describe('BinaryTree', () => {
it('should isSubtreeBST', () => {
expect(tree.toVisual()).toBe('');
tree.addMany([4, 2, 6, 1, 3, 5, 7, 4]);
expect(tree.toVisual()).toBe(
expect(tree.toVisual()).toBe('N for null\n' +
' ___4___ \n' +
' / \\ \n' +
' _2_ _6_ \n' +
' / \\ / \\ \n' +
' 1 3 5 7 \n' +
' \n'
);
' / \\ \n' +
' _2_ _6_ \n' +
' / \\ / \\ \n' +
' 1 3 5 7 \n' +
' \n');
const visualized = tree.toVisual(undefined, { isShowUndefined: true, isShowNull: true, isShowRedBlackNIL: true });
expect(visualized).toBe(
'U for undefined\n' +
' N for null\n' +
' S for Sentinel Node(NIL)\n' +
' _______4_______ \n' +
' / \\ \n' +
' ___2___ ___6___ \n' +
' / \\ / \\ \n' +
' _1_ _3_ _5_ _7_ \n' +
' / \\ / \\ / \\ / \\ \n' +
' U U U U U U U U \n' +
' \n'
'N for null\n' +
'S for Sentinel Node(NIL)\n' +
' _______4_______ \n' +
' / \\ \n' +
' ___2___ ___6___ \n' +
' / \\ / \\ \n' +
' _1_ _3_ _5_ _7_ \n' +
' / \\ / \\ / \\ / \\ \n' +
' U U U U U U U U \n' +
' \n'
);
expect(tree.isBST(tree.getNode(4), 'RECURSIVE')).toBe(true);

View file

@ -16,22 +16,27 @@ describe('BST operations test', () => {
expect(isAdd0).toBe(true);
expect(bst.get(0)).toBe('0');
});
it('should addMany undefined and null', () => {
const bst = new BST<number, string>();
const addManyWithUndefined = bst.addMany([1, undefined, 3]);
// TODO
// expect(addManyWithUndefined).toEqual([true, false, true]);
expect(addManyWithUndefined).toEqual([true, true]);
expect(addManyWithUndefined).toEqual([true, false, true]);
expect(bst.get(undefined)).toBe(undefined);
const addManyWithNull = bst.addMany([1, null, 3, 4]);
// TODO
// expect(addManyWithNull).toEqual([false, false, false, true]);
expect(addManyWithNull).toEqual([true, true, true]);
expect(addManyWithNull).toEqual([true, false, true, true]);
const addManyEntriesWithNull = bst.addMany([
[1, '1'],
[null, 'null'],
[3, '3'],
[4, '4']
]);
expect(addManyEntriesWithNull).toEqual([true, false, true, true]);
expect(bst.get(null)).toBe(undefined);
const node0 = bst.add(0, '0');
expect(node0).toBe(true);
expect(bst.get(0)).toBe('0');
});
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const bst = new BST<number, number>();
expect(bst).toBeInstanceOf(BST);