feat: Replace the AVLTree with a Red-Black Tree to implement TreeMultiMap, preserving the implementation of TreeMultiMap using AVLTree and renaming it as AVLTreeMultiMap.

This commit is contained in:
Revone 2024-01-08 22:22:41 +08:00
parent e2ab386df3
commit 465744c2ec
18 changed files with 1336 additions and 148 deletions

View file

@ -2,4 +2,5 @@ src/types/data-structures/binary-tree/binary-tree.ts
src/types/data-structures/binary-tree/bst.ts
src/types/data-structures/binary-tree/avl-tree.ts
src/types/data-structures/binary-tree/rb-tree.ts
src/types/data-structures/binary-tree/tree-multimap.ts
src/types/data-structures/binary-tree/tree-multi-map.ts
src/types/data-structures/binary-tree/avl-tree-multi-map.ts

View file

@ -116,7 +116,7 @@ yarn add data-structure-typed
```js
import {
Heap, Graph, Queue, Deque, PriorityQueue, BST, Trie, DoublyLinkedList,
AVLTree, SinglyLinkedList, DirectedGraph, RedBlackTree, TreeMultimap,
AVLTree, SinglyLinkedList, DirectedGraph, RedBlackTree, TreeMultiMap,
DirectedVertex, Stack, AVLTreeNode
} from 'data-structure-typed';
```
@ -273,7 +273,7 @@ avl.print();
// / \
// 7 9
const treeMulti = new TreeMultimap(entries);
const treeMulti = new TreeMultiMap(entries);
treeMulti.print();
// ___4___
// / \
@ -516,7 +516,7 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key) // ['A', 'B', '
<td>Tree Multimap</td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/TreeMultimap.html"><span>View</span></a></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/TreeMultiMap.html"><span>View</span></a></td>
</tr>
<tr>
<td>Heap</td>
@ -702,13 +702,13 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key) // ['A', 'B', '
<td>-</td>
</tr>
<tr>
<td>TreeMultimap&lt;K, V&gt;</td>
<td>TreeMultiMap&lt;K, V&gt;</td>
<td>multimap&lt;K, V&gt;</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>TreeMultimap&lt;E&gt;</td>
<td>TreeMultiMap&lt;E&gt;</td>
<td>multiset&lt;T&gt;</td>
<td>-</td>
<td>-</td>
@ -1017,7 +1017,7 @@ Copy the code below into the script tag of your HTML, and you're good to go with
const {Heap} = dataStructureTyped;
const {
BinaryTree, Graph, Queue, Stack, PriorityQueue, BST, Trie, DoublyLinkedList,
AVLTree, MinHeap, SinglyLinkedList, DirectedGraph, TreeMultimap,
AVLTree, MinHeap, SinglyLinkedList, DirectedGraph, TreeMultiMap,
DirectedVertex, AVLTreeNode
} = dataStructureTyped;
```

View file

@ -121,7 +121,7 @@ yarn add data-structure-typed
```js
import {
BinaryTree, Graph, Queue, Stack, PriorityQueue, BST, Trie, DoublyLinkedList,
AVLTree, MinHeap, SinglyLinkedList, DirectedGraph, TreeMultimap,
AVLTree, MinHeap, SinglyLinkedList, DirectedGraph, TreeMultiMap,
DirectedVertex, AVLTreeNode
} from 'data-structure-typed';
```
@ -148,7 +148,7 @@ import {
const {Heap} = dataStructureTyped;
const {
BinaryTree, Graph, Queue, Stack, PriorityQueue, BST, Trie, DoublyLinkedList,
AVLTree, MinHeap, SinglyLinkedList, DirectedGraph, TreeMultimap,
AVLTree, MinHeap, SinglyLinkedList, DirectedGraph, TreeMultiMap,
DirectedVertex, AVLTreeNode
} = dataStructureTyped;
```
@ -442,7 +442,7 @@ avl.print();
// / \
// 7 9
const treeMulti = new TreeMultimap(entries);
const treeMulti = new TreeMultiMap(entries);
treeMulti.print();
// ___4___
// / \
@ -563,7 +563,7 @@ avl2.print();
<td>Tree Multimap</td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/TreeMultimap.html"><span>View</span></a></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/TreeMultiMap.html"><span>View</span></a></td>
</tr>
<tr>
<td>Heap</td>
@ -743,13 +743,13 @@ avl2.print();
<td>-</td>
</tr>
<tr>
<td>TreeMultimap&lt;K, V&gt;</td>
<td>TreeMultiMap&lt;K, V&gt;</td>
<td>multimap&lt;K, V&gt;</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>TreeMultimap&lt;E&gt;</td>
<td>TreeMultiMap&lt;E&gt;</td>
<td>multiset&lt;T&gt;</td>
<td>-</td>
<td>-</td>

View file

@ -6,22 +6,22 @@
* @license MIT License
*/
import type {
AVLTreeMultiMapNested,
AVLTreeMultiMapNodeNested,
AVLTreeMultiMapOptions,
BinaryTreeDeleteResult,
BSTNKeyOrNode,
BTNCallback,
KeyOrNodeOrEntry,
TreeMultimapNested,
TreeMultimapNodeNested,
TreeMultimapOptions
KeyOrNodeOrEntry
} from '../../types';
import { FamilyPosition, IterationType } from '../../types';
import { IBinaryTree } from '../../interfaces';
import { AVLTree, AVLTreeNode } from './avl-tree';
export class TreeMultimapNode<
export class AVLTreeMultiMapNode<
K = any,
V = any,
NODE extends TreeMultimapNode<K, V, NODE> = TreeMultimapNodeNested<K, V>
NODE extends AVLTreeMultiMapNode<K, V, NODE> = AVLTreeMultiMapNodeNested<K, V>
> extends AVLTreeNode<K, V, NODE> {
/**
* The constructor function initializes a BinaryTreeNode object with a key, value, and count.
@ -59,17 +59,17 @@ export class TreeMultimapNode<
}
/**
* The only distinction between a TreeMultimap and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters.
* The only distinction between a AVLTreeMultiMap and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters.
*/
export class TreeMultimap<
export class AVLTreeMultiMap<
K = any,
V = any,
NODE extends TreeMultimapNode<K, V, NODE> = TreeMultimapNode<K, V, TreeMultimapNodeNested<K, V>>,
TREE extends TreeMultimap<K, V, NODE, TREE> = TreeMultimap<K, V, NODE, TreeMultimapNested<K, V, NODE>>
NODE extends AVLTreeMultiMapNode<K, V, NODE> = AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNodeNested<K, V>>,
TREE extends AVLTreeMultiMap<K, V, NODE, TREE> = AVLTreeMultiMap<K, V, NODE, AVLTreeMultiMapNested<K, V, NODE>>
>
extends AVLTree<K, V, NODE, TREE>
implements IBinaryTree<K, V, NODE, TREE> {
constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>> = [], options?: TreeMultimapOptions<K>) {
constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>> = [], options?: AVLTreeMultiMapOptions<K>) {
super([], options);
if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries);
}
@ -98,20 +98,20 @@ export class TreeMultimap<
* @returns A new instance of the BSTNode class with the specified key, value, and count (if provided).
*/
override createNode(key: K, value?: V, count?: number): NODE {
return new TreeMultimapNode(key, value, count) as NODE;
return new AVLTreeMultiMapNode(key, value, count) as NODE;
}
/**
* The function creates a new TreeMultimap object with the specified options and returns it.
* The function creates a new AVLTreeMultiMap object with the specified options and returns it.
* @param [options] - The `options` parameter is an optional object that contains additional
* configuration options for creating the `TreeMultimap` object. It can include properties such as
* configuration options for creating the `AVLTreeMultiMap` object. It can include properties such as
* `iterationType` and `variant`, which are used to specify the type of iteration and the variant of
* the tree, respectively. These properties can be
* @returns a new instance of the `TreeMultimap` class, with the provided options merged with the
* @returns a new instance of the `AVLTreeMultiMap` class, with the provided options merged with the
* default options. The returned value is casted as `TREE`.
*/
override createTree(options?: TreeMultimapOptions<K>): TREE {
return new TreeMultimap<K, V, NODE, TREE>([], {
override createTree(options?: AVLTreeMultiMapOptions<K>): TREE {
return new AVLTreeMultiMap<K, V, NODE, TREE>([], {
iterationType: this.iterationType,
variant: this.variant,
...options
@ -155,13 +155,13 @@ export class TreeMultimap<
}
/**
* The function checks if an keyOrNodeOrEntry is an instance of the TreeMultimapNode class.
* The function checks if an keyOrNodeOrEntry is an instance of the AVLTreeMultiMapNode class.
* @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry<K, V, NODE>`.
* @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the TreeMultimapNode
* @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the AVLTreeMultiMapNode
* class.
*/
override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>): keyOrNodeOrEntry is NODE {
return keyOrNodeOrEntry instanceof TreeMultimapNode;
return keyOrNodeOrEntry instanceof AVLTreeMultiMapNode;
}
/**

View file

@ -708,9 +708,8 @@ export class BST<
const compared = this._compare(cur.key, targetKey);
if (compared === lesserOrGreater) ans.push(callback(cur));
if (!cur.left && !cur.right) return;
if (cur.left && this._compare(cur.left.key, targetKey) === lesserOrGreater) _traverse(cur.left);
if (cur.right && this._compare(cur.right.key, targetKey) === lesserOrGreater) _traverse(cur.right);
if (this.isRealNode(cur.left)) _traverse(cur.left);
if (this.isRealNode(cur.right)) _traverse(cur.right);
};
_traverse(this.root);
@ -719,12 +718,12 @@ export class BST<
const queue = new Queue<NODE>([this.root]);
while (queue.size > 0) {
const cur = queue.shift();
if (cur) {
if (this.isRealNode(cur)) {
const compared = this._compare(cur.key, targetKey);
if (compared === lesserOrGreater) ans.push(callback(cur));
if (cur.left && this._compare(cur.left.key, targetKey) === lesserOrGreater) queue.push(cur.left);
if (cur.right && this._compare(cur.right.key, targetKey) === lesserOrGreater) queue.push(cur.right);
if (this.isRealNode(cur.left)) queue.push(cur.left);
if (this.isRealNode(cur.right)) queue.push(cur.right);
}
}
return ans;

View file

@ -4,4 +4,5 @@ export * from './binary-indexed-tree';
export * from './segment-tree';
export * from './avl-tree';
export * from './rb-tree';
export * from './tree-multimap';
export * from './avl-tree-multi-map';
export * from './tree-multi-map';

View file

@ -527,12 +527,14 @@ export class RedBlackTree<
*/
protected _fixInsert(k: NODE): void {
let u: NODE | undefined;
while (k.parent && k.parent.color === 1) {
while (k.parent && k.parent.color === RBTNColor.RED) {
if (k.parent.parent && k.parent === k.parent.parent.right) {
u = k.parent.parent.left;
if (u && u.color === 1) {
u.color = RBTNColor.BLACK;
if (u && u.color === RBTNColor.RED) {
// Delay color flip
k.parent.color = RBTNColor.BLACK;
u.color = RBTNColor.BLACK;
k.parent.parent.color = RBTNColor.RED;
k = k.parent.parent;
} else {
@ -541,16 +543,20 @@ export class RedBlackTree<
this._rightRotate(k);
}
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
// Check color before rotation
if (k.parent!.color === RBTNColor.RED) {
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
}
this._leftRotate(k.parent!.parent!);
}
} else {
u = k.parent.parent!.right;
u = k.parent!.parent!.right;
if (u && u.color === 1) {
u.color = RBTNColor.BLACK;
if (u && u.color === RBTNColor.RED) {
// Delay color flip
k.parent.color = RBTNColor.BLACK;
u.color = RBTNColor.BLACK;
k.parent.parent!.color = RBTNColor.RED;
k = k.parent.parent!;
} else {
@ -559,11 +565,15 @@ export class RedBlackTree<
this._leftRotate(k);
}
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
// Check color before rotation
if (k.parent!.color === RBTNColor.RED) {
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
}
this._rightRotate(k.parent!.parent!);
}
}
if (k === this.root) {
break;
}

View file

@ -0,0 +1,463 @@
/**
* data-structure-typed
*
* @author Tyler Zeng
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {
BinaryTreeDeleteResult,
BSTNKeyOrNode,
BTNCallback,
KeyOrNodeOrEntry,
TreeMultiMapNested,
TreeMultiMapNodeNested,
TreeMultiMapOptions
} from '../../types';
import { IterationType, RBTNColor } from '../../types';
import { IBinaryTree } from '../../interfaces';
import { RedBlackTree, RedBlackTreeNode } from './rb-tree';
export class TreeMultiMapNode<
K = any,
V = any,
NODE extends TreeMultiMapNode<K, V, NODE> = TreeMultiMapNodeNested<K, V>
> extends RedBlackTreeNode<K, V, NODE> {
/**
* The constructor function initializes an instance of a class with a key, value, and count.
* @param {K} key - The key parameter is of type K, which represents the type of the key for the
* constructor. It is required and must be provided when creating an instance of the class.
* @param {V} [value] - The `value` parameter is an optional parameter of type `V`. It represents the
* value associated with the key in the constructor. If no value is provided, it will be `undefined`.
* @param [count=1] - The "count" parameter is an optional parameter that specifies the number of
* times the key-value pair should be repeated. If no value is provided for "count", it defaults to
* 1.
*/
constructor(key: K, value?: V, count = 1) {
super(key, value);
this.count = count;
}
protected _count: number = 1;
/**
* The function returns the value of the private variable _count.
* @returns The count property of the object, which is of type number.
*/
get count(): number {
return this._count;
}
/**
* The above function sets the value of the count property.
* @param {number} value - The value parameter is of type number, which means it can accept any
* numeric value.
*/
set count(value: number) {
this._count = value;
}
}
export class TreeMultiMap<
K = any,
V = any,
NODE extends TreeMultiMapNode<K, V, NODE> = TreeMultiMapNode<K, V, TreeMultiMapNodeNested<K, V>>,
TREE extends TreeMultiMap<K, V, NODE, TREE> = TreeMultiMap<K, V, NODE, TreeMultiMapNested<K, V, NODE>>
>
extends RedBlackTree<K, V, NODE, TREE>
implements IBinaryTree<K, V, NODE, TREE> {
/**
* The constructor function initializes a new instance of the TreeMultiMap class with optional
* initial keys, nodes, or entries.
* @param keysOrNodesOrEntries - The `keysOrNodesOrEntries` parameter is an iterable object that can
* contain keys, nodes, or entries. It is used to initialize the TreeMultiMap with the provided keys,
* nodes, or entries.
* @param [options] - The `options` parameter is an optional object that can be passed to the
* constructor. It allows you to customize the behavior of the `TreeMultiMap` instance.
*/
constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>> = [], options?: TreeMultiMapOptions<K>) {
super([], options);
if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries);
}
protected _count = 0;
// TODO the _count is not accurate after nodes count modified
/**
* The function calculates the sum of the count property of all nodes in a tree structure.
* @returns the sum of the count property of all nodes in the tree.
*/
get count(): number {
let sum = 0;
this.dfs(node => (sum += node.count));
return sum;
// return this._count;
}
/**
* The function creates a new TreeMultiMapNode object with the specified key, value, and count.
* @param {K} key - The key parameter represents the key of the node being created. It is of type K,
* which is a generic type that can be replaced with any specific type when using the function.
* @param {V} [value] - The `value` parameter is an optional parameter that represents the value
* associated with the key in the node. It is of type `V`, which can be any data type.
* @param {number} [count] - The `count` parameter represents the number of occurrences of a
* key-value pair in the TreeMultiMap. It is an optional parameter, so if it is not provided, it will
* default to 1.
* @returns a new instance of the TreeMultiMapNode class, casted as NODE.
*/
override createNode(key: K, value?: V, count?: number): NODE {
return new TreeMultiMapNode(key, value, count) as NODE;
}
/**
* The function creates a new instance of a TreeMultiMap with the specified options and returns it.
* @param [options] - The `options` parameter is an optional object that contains additional
* configuration options for creating the `TreeMultiMap`. It can include properties such as
* `keyComparator`, `valueComparator`, `allowDuplicates`, etc.
* @returns a new instance of the `TreeMultiMap` class, with the provided options merged with the
* existing `iterationType` option. The returned value is casted as `TREE`.
*/
override createTree(options?: TreeMultiMapOptions<K>): TREE {
return new TreeMultiMap<K, V, NODE, TREE>([], {
iterationType: this.iterationType,
...options
}) as TREE;
}
/**
* The function `keyValueOrEntryToNode` takes a key, value, and count and returns a node if the input
* is valid.
* @param keyOrNodeOrEntry - The parameter `keyOrNodeOrEntry` can be of type `KeyOrNodeOrEntry<K, V,
* NODE>`. It can accept three types of values:
* @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the
* value associated with a key in a key-value pair.
* @param [count=1] - The count parameter is an optional parameter that specifies the number of times
* the key-value pair should be added to the node. If not provided, it defaults to 1.
* @returns a NODE object or undefined.
*/
override keyValueOrEntryToNode(
keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>,
value?: V,
count = 1
): NODE | undefined {
let node: NODE | undefined;
if (keyOrNodeOrEntry === undefined || keyOrNodeOrEntry === null) {
return;
} else if (this.isNode(keyOrNodeOrEntry)) {
node = keyOrNodeOrEntry;
} else if (this.isEntry(keyOrNodeOrEntry)) {
const [key, value] = keyOrNodeOrEntry;
if (key === undefined || key === null) {
return;
} else {
node = this.createNode(key, value, count);
}
} else if (!this.isNode(keyOrNodeOrEntry)) {
node = this.createNode(keyOrNodeOrEntry, value, count);
} else {
return;
}
return node;
}
/**
* The function "isNode" checks if a given key, node, or entry is an instance of the TreeMultiMapNode
* class.
* @param keyOrNodeOrEntry - The parameter `keyOrNodeOrEntry` can be of type `KeyOrNodeOrEntry<K, V,
* NODE>`.
* @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntry` is an instance
* of the `TreeMultiMapNode` class.
*/
override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>): keyOrNodeOrEntry is NODE {
return keyOrNodeOrEntry instanceof TreeMultiMapNode;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The function overrides the add method in TypeScript and adds a new node to the data structure.
* @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can accept three types of values:
* @param {V} [value] - The `value` parameter represents the value associated with the key in the
* data structure.
* @param [count=1] - The `count` parameter represents the number of times the key-value pair should
* be added to the data structure. By default, it is set to 1, meaning that the key-value pair will
* be added once. However, you can specify a different value for `count` if you want to add
* @returns a boolean value.
*/
override add(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>, value?: V, count = 1): boolean {
const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value, count);
if (newNode === undefined) return false;
const orgNodeCount = newNode?.count || 0;
const inserted = super.add(newNode);
if (inserted) {
this._count += orgNodeCount;
}
return true;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `delete` function in a TypeScript class is used to delete nodes from a binary tree based on a
* given identifier, and it returns an array of results containing information about the deleted
* nodes.
* @param {ReturnType<C> | null | undefined} identifier - The identifier parameter is the value used
* to identify the node to be deleted. It can be of any type that is returned by the callback
* function. It can also be null or undefined if no node needs to be deleted.
* @param {C} callback - The `callback` parameter is a function that takes a node of type `NODE` as
* input and returns a value of type `ReturnType<C>`. It is used to determine if a node matches the
* identifier for deletion. If no callback is provided, the `_defaultOneParamCallback` function is
* used
* @param [ignoreCount=false] - A boolean value indicating whether to ignore the count of the target
* node when performing deletion. If set to true, the count of the target node will not be considered
* and the node will be deleted regardless of its count. If set to false (default), the count of the
* target node will be decremented
* @returns an array of BinaryTreeDeleteResult<NODE> objects.
*/
override delete<C extends BTNCallback<NODE>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this._defaultOneParamCallback as C,
ignoreCount = false
): BinaryTreeDeleteResult<NODE>[] {
const deleteResults: BinaryTreeDeleteResult<NODE>[] = [];
if (identifier === null) return deleteResults;
// Helper function to perform deletion
const deleteHelper = (node: NODE | undefined): void => {
// Initialize targetNode to the sentinel node
let targetNode: NODE = this._Sentinel;
let currentNode: NODE | undefined;
// Find the node to be deleted based on the identifier
while (node !== this._Sentinel) {
// Update targetNode if the current node matches the identifier
if (node && callback(node) === identifier) {
targetNode = node;
}
// Move to the right or left based on the comparison with the identifier
if (node && identifier && callback(node) <= identifier) {
node = node.right;
} else {
node = node?.left;
}
}
// If the target node is not found, decrement size and return
if (targetNode === this._Sentinel) {
return;
}
if (ignoreCount || targetNode.count <= 1) {
// Store the parent of the target node and its original color
let parentNode = targetNode;
let parentNodeOriginalColor: number = parentNode.color;
// Handle deletion based on the number of children of the target node
if (targetNode.left === this._Sentinel) {
// Target node has no left child - deletion case 1
currentNode = targetNode.right;
this._rbTransplant(targetNode, targetNode.right!);
} else if (targetNode.right === this._Sentinel) {
// Target node has no right child - deletion case 2
currentNode = targetNode.left;
this._rbTransplant(targetNode, targetNode.left!);
} else {
// Target node has both left and right children - deletion case 3
parentNode = this.getLeftMost(targetNode.right)!;
parentNodeOriginalColor = parentNode.color;
currentNode = parentNode.right;
if (parentNode.parent === targetNode) {
// Target node's right child becomes its parent's left child
currentNode!.parent = parentNode;
} else {
// Replace parentNode with its right child and update connections
this._rbTransplant(parentNode, parentNode.right!);
parentNode.right = targetNode.right;
parentNode.right!.parent = parentNode;
}
// Replace the target node with its in-order successor
this._rbTransplant(targetNode, parentNode);
parentNode.left = targetNode.left;
parentNode.left!.parent = parentNode;
parentNode.color = targetNode.color;
}
// Fix the Red-Black Tree properties after deletion
if (parentNodeOriginalColor === RBTNColor.BLACK) {
this._fixDelete(currentNode!);
}
// Decrement the size and store information about the deleted node
this._size--;
this._count -= targetNode.count;
deleteResults.push({ deleted: targetNode, needBalanced: undefined });
} else {
targetNode.count--;
this._count--;
}
};
// Call the helper function with the root of the tree
deleteHelper(this.root);
// Return the result array
return deleteResults;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The "clear" function overrides the parent class's "clear" function and also resets the count to
* zero.
*/
override clear() {
super.clear();
this._count = 0;
}
/**
* Time Complexity: O(n log n)
* Space Complexity: O(log n)
*/
/**
* Time Complexity: O(n log n)
* Space Complexity: O(log n)
*
* The `perfectlyBalance` function takes a sorted array of nodes and builds a balanced binary search
* tree using either a recursive or iterative approach.
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
* type of iteration to use when building the balanced binary search tree. It can have two possible
* values:
* @returns a boolean value.
*/
override perfectlyBalance(iterationType = this.iterationType): boolean {
const sorted = this.dfs(node => node, 'in'),
n = sorted.length;
if (sorted.length < 1) return false;
this.clear();
if (iterationType === IterationType.RECURSIVE) {
const buildBalanceBST = (l: number, r: number) => {
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
buildBalanceBST(0, n - 1);
return true;
} else {
const stack: [[number, number]] = [[0, n - 1]];
while (stack.length > 0) {
const popped = stack.pop();
if (popped) {
const [l, r] = popped;
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
}
}
return true;
}
}
/**
* Time complexity: O(n)
* Space complexity: O(n)
*/
/**
* Time complexity: O(n)
* Space complexity: O(n)
*
* The function overrides the clone method to create a deep copy of a tree object.
* @returns The `clone()` method is returning a cloned instance of the `TREE` object.
*/
override clone(): TREE {
const cloned = this.createTree();
this.bfs(node => cloned.add(node.key, node.value, node.count));
return cloned;
}
/**
* The function swaps the properties of two nodes in a binary search tree.
* @param srcNode - The source node that needs to be swapped with the destination node. It can be
* either a key or a node object.
* @param destNode - The `destNode` parameter is the node in the binary search tree where the
* properties will be swapped with the `srcNode`.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
* If both `srcNode` and `destNode` are valid nodes, the method swaps their `key`, `value`, `count`,
* and `color` properties. If the swapping is successful, the method returns the modified `destNode`.
* If either `srcNode` or `destNode` is
*/
protected override _swapProperties(
srcNode: BSTNKeyOrNode<K, NODE>,
destNode: BSTNKeyOrNode<K, NODE>
): NODE | undefined {
srcNode = this.ensureNode(srcNode);
destNode = this.ensureNode(destNode);
if (srcNode && destNode) {
const { key, value, count, color } = destNode;
const tempNode = this.createNode(key, value, count);
if (tempNode) {
tempNode.color = color;
destNode.key = srcNode.key;
destNode.value = srcNode.value;
destNode.count = srcNode.count;
destNode.color = srcNode.color;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
srcNode.count = tempNode.count;
srcNode.color = tempNode.color;
}
return destNode;
}
return undefined;
}
/**
* The function replaces an old node with a new node and updates the count property of the new node.
* @param {NODE} oldNode - The `oldNode` parameter is of type `NODE` and represents the node that
* needs to be replaced in the data structure.
* @param {NODE} newNode - The `newNode` parameter is an object of type `NODE`.
* @returns The method is returning the result of calling the `_replaceNode` method from the
* superclass, after updating the `count` property of the `newNode` object.
*/
protected _replaceNode(oldNode: NODE, newNode: NODE): NODE {
newNode.count = oldNode.count + newNode.count;
return super._replaceNode(oldNode, newNode);
}
}

View file

@ -0,0 +1,8 @@
import { AVLTreeMultiMap, AVLTreeMultiMapNode } from '../../../data-structures';
import type { AVLTreeOptions } from './avl-tree';
export type AVLTreeMultiMapNodeNested<K, V> = AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNode<K, V, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type AVLTreeMultiMapNested<K, V, N extends AVLTreeMultiMapNode<K, V, N>> = AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, AVLTreeMultiMap<K, V, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type AVLTreeMultiMapOptions<K> = AVLTreeOptions<K> & {}

View file

@ -2,5 +2,6 @@ export * from './binary-tree';
export * from './bst';
export * from './avl-tree';
export * from './segment-tree';
export * from './tree-multimap';
export * from './avl-tree-multi-map';
export * from './rb-tree';
export * from './tree-multi-map';

View file

@ -0,0 +1,8 @@
import { TreeMultiMap, TreeMultiMapNode } from '../../../data-structures';
import type { RBTreeOptions } from './rb-tree';
export type TreeMultiMapNodeNested<K, V> = TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, TreeMultiMapNode<K, V, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultiMapNested<K, V, N extends TreeMultiMapNode<K, V, N>> = TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, TreeMultiMap<K, V, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultiMapOptions<K> = RBTreeOptions<K> & {}

View file

@ -1,8 +0,0 @@
import { TreeMultimap, TreeMultimapNode } from '../../../data-structures';
import type { AVLTreeOptions } from './avl-tree';
export type TreeMultimapNodeNested<K, V> = TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, TreeMultimapNode<K, V, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultimapNested<K, V, N extends TreeMultimapNode<K, V, N>> = TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, TreeMultimap<K, V, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultimapOptions<K> = AVLTreeOptions<K> & {}

View file

@ -232,7 +232,7 @@
RedBlackTree,
SinglyLinkedList,
Stack,
TreeMultimap,
TreeMultiMap,
Trie
} = dataStructureTyped;
const orgArr = [6, 1, 2, 7, 5, 3, 4, 9, 8];
@ -302,7 +302,7 @@
// / \
// 7 9
const treeMulti = new TreeMultimap(entries);
const treeMulti = new TreeMultiMap(entries);
treeMulti.print();
// ___4___
// / \

View file

@ -1,20 +1,20 @@
import {
AVLTreeMultiMap,
AVLTreeMultiMapNode,
AVLTreeNode,
BinaryTreeNode,
BSTNode,
CP,
IterationType,
TreeMultimap,
TreeMultimapNode
IterationType
} from '../../../../src';
import { isDebugTest } from '../../../config';
const isDebug = isDebugTest;
describe('TreeMultimap count', () => {
let tm: TreeMultimap<number>;
describe('AVLTreeMultiMap count', () => {
let tm: AVLTreeMultiMap<number>;
beforeEach(() => {
tm = new TreeMultimap<number>();
tm = new AVLTreeMultiMap<number>();
});
it('Should added isolated node count ', () => {
tm.addMany([
@ -24,7 +24,7 @@ describe('TreeMultimap count', () => {
[4, 4],
[5, 5]
]);
const newNode = new TreeMultimapNode(3, 33, 10);
const newNode = new AVLTreeMultiMapNode(3, 33, 10);
tm.add(newNode);
expect(tm.count).toBe(15);
});
@ -40,11 +40,11 @@ describe('TreeMultimap count', () => {
});
});
describe('TreeMultimap operations test1', () => {
describe('AVLTreeMultiMap operations test1', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const treeMultimap = new TreeMultimap();
const treeMultimap = new AVLTreeMultiMap();
expect(treeMultimap instanceof TreeMultimap);
expect(treeMultimap instanceof AVLTreeMultiMap);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
@ -66,7 +66,7 @@ describe('TreeMultimap operations test1', () => {
[5, 5]
];
treeMultimap.addMany(idAndValues);
expect(treeMultimap.root instanceof TreeMultimapNode);
expect(treeMultimap.root instanceof AVLTreeMultiMapNode);
if (treeMultimap.root) expect(treeMultimap.root.key == 11);
@ -99,17 +99,17 @@ describe('TreeMultimap operations test1', () => {
node15 && treeMultimap.dfs(node => (subTreeSum += node.key), 'pre', 15);
expect(subTreeSum).toBe(31);
let lesserSum = 0;
treeMultimap.lesserOrGreaterTraverse((node: TreeMultimapNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(21);
treeMultimap.lesserOrGreaterTraverse((node: AVLTreeMultiMapNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(node15 instanceof TreeMultimapNode);
if (node15 instanceof TreeMultimapNode) {
expect(node15 instanceof AVLTreeMultiMapNode);
if (node15 instanceof AVLTreeMultiMapNode) {
const subTreeAdd = treeMultimap.dfs(node => (node.count += 1), 'pre', 15);
expect(subTreeAdd);
}
const node11 = treeMultimap.getNode(11);
expect(node11 instanceof TreeMultimapNode);
if (node11 instanceof TreeMultimapNode) {
expect(node11 instanceof AVLTreeMultiMapNode);
if (node11 instanceof AVLTreeMultiMapNode) {
const allGreaterNodesAdded = treeMultimap.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11);
expect(allGreaterNodesAdded);
}
@ -257,14 +257,14 @@ describe('TreeMultimap operations test1', () => {
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultimap.count).toBe(4);
expect(treeMultimap.count).toBe(8);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objTreeMultimap = new TreeMultimap<number, { key: number; keyA: number }>();
expect(objTreeMultimap).toBeInstanceOf(TreeMultimap);
objTreeMultimap.add([11, { key: 11, keyA: 11 }]);
objTreeMultimap.add([3, { key: 3, keyA: 3 }]);
const objAVLTreeMultiMap = new AVLTreeMultiMap<number, { key: number; keyA: number }>();
expect(objAVLTreeMultiMap).toBeInstanceOf(AVLTreeMultiMap);
objAVLTreeMultiMap.add([11, { key: 11, keyA: 11 }]);
objAVLTreeMultiMap.add([3, { key: 3, keyA: 3 }]);
const values: [number, { key: number; keyA: number }][] = [
[15, { key: 15, keyA: 15 }],
[1, { key: 1, keyA: 1 }],
@ -282,23 +282,23 @@ describe('TreeMultimap operations test1', () => {
[5, { key: 5, keyA: 5 }]
];
objTreeMultimap.addMany(values);
objAVLTreeMultiMap.addMany(values);
expect(objTreeMultimap.root).toBeInstanceOf(TreeMultimapNode);
expect(objAVLTreeMultiMap.root).toBeInstanceOf(AVLTreeMultiMapNode);
if (objTreeMultimap.root) expect(objTreeMultimap.root.key).toBe(6);
if (objAVLTreeMultiMap.root) expect(objAVLTreeMultiMap.root.key).toBe(6);
expect(objTreeMultimap.count).toBe(16);
expect(objAVLTreeMultiMap.count).toBe(16);
expect(objTreeMultimap.has(6)).toBe(true);
expect(objAVLTreeMultiMap.has(6)).toBe(true);
});
});
describe('TreeMultimap operations test recursively1', () => {
describe('AVLTreeMultiMap operations test recursively1', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const treeMultimap = new TreeMultimap<number>([], { iterationType: IterationType.RECURSIVE });
const treeMultimap = new AVLTreeMultiMap<number>([], { iterationType: IterationType.RECURSIVE });
expect(treeMultimap instanceof TreeMultimap);
expect(treeMultimap instanceof AVLTreeMultiMap);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
@ -320,7 +320,7 @@ describe('TreeMultimap operations test recursively1', () => {
[5, 5]
];
treeMultimap.addMany(idAndValues);
expect(treeMultimap.root).toBeInstanceOf(TreeMultimapNode);
expect(treeMultimap.root).toBeInstanceOf(AVLTreeMultiMapNode);
if (treeMultimap.root) expect(treeMultimap.root.key).toBe(6);
@ -353,17 +353,17 @@ describe('TreeMultimap operations test recursively1', () => {
node15 && treeMultimap.dfs(node => (subTreeSum += node.key), 'pre', 15);
expect(subTreeSum).toBe(31);
let lesserSum = 0;
treeMultimap.lesserOrGreaterTraverse((node: TreeMultimapNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(21);
treeMultimap.lesserOrGreaterTraverse((node: AVLTreeMultiMapNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(node15 instanceof TreeMultimapNode);
if (node15 instanceof TreeMultimapNode) {
expect(node15 instanceof AVLTreeMultiMapNode);
if (node15 instanceof AVLTreeMultiMapNode) {
const subTreeAdd = treeMultimap.dfs(node => (node.count += 1), 'pre', 15);
expect(subTreeAdd);
}
const node11 = treeMultimap.getNode(11);
expect(node11 instanceof TreeMultimapNode);
if (node11 instanceof TreeMultimapNode) {
expect(node11 instanceof AVLTreeMultiMapNode);
if (node11 instanceof AVLTreeMultiMapNode) {
const allGreaterNodesAdded = treeMultimap.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11);
expect(allGreaterNodesAdded);
}
@ -511,14 +511,14 @@ describe('TreeMultimap operations test recursively1', () => {
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultimap.count).toBe(4);
expect(treeMultimap.count).toBe(8);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objTreeMultimap = new TreeMultimap<number, { key: number; keyA: number }>();
expect(objTreeMultimap).toBeInstanceOf(TreeMultimap);
objTreeMultimap.add([11, { key: 11, keyA: 11 }]);
objTreeMultimap.add([3, { key: 3, keyA: 3 }]);
const objAVLTreeMultiMap = new AVLTreeMultiMap<number, { key: number; keyA: number }>();
expect(objAVLTreeMultiMap).toBeInstanceOf(AVLTreeMultiMap);
objAVLTreeMultiMap.add([11, { key: 11, keyA: 11 }]);
objAVLTreeMultiMap.add([3, { key: 3, keyA: 3 }]);
const values: [number, { key: number; keyA: number }][] = [
[15, { key: 15, keyA: 15 }],
[1, { key: 1, keyA: 1 }],
@ -536,27 +536,27 @@ describe('TreeMultimap operations test recursively1', () => {
[5, { key: 5, keyA: 5 }]
];
objTreeMultimap.addMany(values);
objAVLTreeMultiMap.addMany(values);
expect(objTreeMultimap.root).toBeInstanceOf(TreeMultimapNode);
expect(objAVLTreeMultiMap.root).toBeInstanceOf(AVLTreeMultiMapNode);
if (objTreeMultimap.root) expect(objTreeMultimap.root.key).toBe(6);
if (objAVLTreeMultiMap.root) expect(objAVLTreeMultiMap.root.key).toBe(6);
expect(objTreeMultimap.count).toBe(16);
expect(objAVLTreeMultiMap.count).toBe(16);
expect(objTreeMultimap.has(6)).toBe(true);
expect(objAVLTreeMultiMap.has(6)).toBe(true);
});
});
describe('TreeMultimap Performance test', function () {
const treeMS = new TreeMultimap<number, number>();
describe('AVLTreeMultiMap Performance test', function () {
const treeMS = new AVLTreeMultiMap<number, number>();
const inputSize = 100000; // Adjust input sizes as needed
beforeEach(() => {
treeMS.clear();
});
it(`Observe the time consumption of TreeMultimap.dfs be good`, function () {
it(`Observe the time consumption of AVLTreeMultiMap.dfs be good`, function () {
const startDFS = performance.now();
const dfs = treeMS.dfs(node => node);
isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length);
@ -574,7 +574,7 @@ describe('TreeMultimap Performance test', function () {
});
it('should the clone method', () => {
function checkTreeStructure(treeMultimap: TreeMultimap<string, number>) {
function checkTreeStructure(treeMultimap: AVLTreeMultiMap<string, number>) {
expect(treeMultimap.size).toBe(4);
expect(treeMultimap.root?.key).toBe('2');
expect(treeMultimap.root?.left?.key).toBe('1');
@ -585,7 +585,7 @@ describe('TreeMultimap Performance test', function () {
expect(treeMultimap.root?.right?.right?.key).toBe('5');
}
const treeMultimap = new TreeMultimap<string, number>();
const treeMultimap = new AVLTreeMultiMap<string, number>();
treeMultimap.addMany([
['2', 2],
['4', 4],
@ -611,10 +611,10 @@ describe('TreeMultimap Performance test', function () {
});
});
describe('TreeMultimap iterative methods test', () => {
let treeMM: TreeMultimap<number, string>;
describe('AVLTreeMultiMap iterative methods test', () => {
let treeMM: AVLTreeMultiMap<number, string>;
beforeEach(() => {
treeMM = new TreeMultimap<number, string>();
treeMM = new AVLTreeMultiMap<number, string>();
treeMM.add(1, 'a', 10);
treeMM.add([2, 'b'], undefined, 10);
treeMM.add([3, 'c'], undefined, 1);

View file

@ -1,4 +1,4 @@
import { AVLTree, BST, BSTVariant, IterationType, RedBlackTree, TreeMultimap } from '../../../../src';
import { AVLTree, BST, BSTVariant, IterationType, RedBlackTree, TreeMultiMap } from '../../../../src';
describe('Overall BinaryTree Test', () => {
it('should perform various operations on BinaryTree', () => {
@ -146,10 +146,9 @@ describe('Overall BinaryTree Test', () => {
expect(clonedAVL.bfs()).toEqual([3, 5, 1, 9, 4, 2, 6]);
});
it('Should clone a TreeMultimap works fine', () => {
const tmm = new TreeMultimap<number>([3, 6, 7, 1, 9], {
it('Should clone a TreeMultiMap works fine', () => {
const tmm = new TreeMultiMap<number>([3, 6, 7, 1, 9], {
iterationType: IterationType.RECURSIVE,
variant: BSTVariant.INVERSE,
extractor: key => key
});
expect(tmm.size).toBe(5);
@ -159,40 +158,40 @@ describe('Overall BinaryTree Test', () => {
tmm.add(5);
tmm.add(4);
expect(tmm.count).toBe(10);
expect(tmm.root?.key).toBe(3);
expect(tmm.root?.left?.key).toBe(7);
expect(tmm.root?.left?.left?.key).toBe(9);
expect(tmm.root?.right?.key).toBe(1);
expect(tmm.root?.right?.left?.key).toBe(2);
expect(tmm.getNodeByKey(7)?.left?.key).toBe(9);
expect(tmm.getHeight()).toBe(3);
expect(tmm.root?.key).toBe(6);
expect(tmm.root?.left?.key).toBe(1);
expect(tmm.root?.left?.left?.key).toBe(NaN);
expect(tmm.root?.right?.key).toBe(7);
expect(tmm.root?.right?.left?.key).toBe(NaN);
expect(tmm.getNodeByKey(7)?.left?.key).toBe(NaN);
expect(tmm.getHeight()).toBe(5);
expect(tmm.has(9)).toBe(true);
expect(tmm.has(7)).toBe(true);
expect(tmm.delete(7)[0].deleted?.key).toBe(7);
expect(tmm.has(7)).toBe(false);
expect(tmm.size).toBe(7);
expect(tmm.count).toBe(9);
expect(tmm.root?.key).toBe(3);
expect(tmm.root?.left?.key).toBe(5);
expect(tmm.root?.right?.key).toBe(1);
expect(tmm.root?.right?.left?.key).toBe(2);
expect(tmm.getNodeByKey(6)?.left?.key).toBe(undefined);
expect(tmm.getHeight()).toBe(3);
expect(tmm.root?.key).toBe(6);
expect(tmm.root?.left?.key).toBe(1);
expect(tmm.root?.right?.key).toBe(9);
expect(tmm.root?.right?.left?.key).toBe(NaN);
expect(tmm.getNodeByKey(6)?.left?.key).toBe(1);
expect(tmm.getHeight()).toBe(5);
expect(tmm.has(9)).toBe(true);
expect(tmm.has(7)).toBe(false);
expect(tmm.bfs()).toEqual([3, 5, 1, 9, 4, 2, 6]);
expect(tmm.bfs()).toEqual([6, 1, 9, 3, 2, 5, 4]);
const clonedTMM = tmm.clone();
expect(clonedTMM.size).toBe(7);
expect(clonedTMM.count).toBe(9);
expect(clonedTMM.root?.key).toBe(3);
expect(clonedTMM.root?.left?.key).toBe(5);
expect(clonedTMM.root?.right?.key).toBe(1);
expect(clonedTMM.root?.right?.left?.key).toBe(2);
expect(clonedTMM.getNodeByKey(6)?.left?.key).toBe(undefined);
expect(clonedTMM.getHeight()).toBe(3);
expect(clonedTMM.root?.key).toBe(6);
expect(clonedTMM.root?.left?.key).toBe(1);
expect(clonedTMM.root?.right?.key).toBe(9);
expect(clonedTMM.root?.right?.left?.key).toBe(NaN);
expect(clonedTMM.getNodeByKey(6)?.left?.key).toBe(1);
expect(clonedTMM.getHeight()).toBe(5);
expect(clonedTMM.has(9)).toBe(true);
expect(clonedTMM.has(7)).toBe(false);
expect(clonedTMM.bfs()).toEqual([3, 5, 1, 9, 4, 2, 6]);
expect(clonedTMM.bfs()).toEqual([6, 1, 9, 3, 2, 5, 4]);
});
it('Should clone a RedBlackTree works fine', () => {

View file

@ -0,0 +1,706 @@
import {
BinaryTreeNode,
BSTNode,
CP,
IterationType,
RedBlackTreeNode,
TreeMultiMap,
TreeMultiMapNode
} from '../../../../src';
import { isDebugTest } from '../../../config';
const isDebug = isDebugTest;
// const isDebug = true;
describe('TreeMultiMap count', () => {
let tm: TreeMultiMap<number>;
beforeEach(() => {
tm = new TreeMultiMap<number>();
});
it('Should added isolated node count ', () => {
tm.addMany([
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]
]);
const newNode = new TreeMultiMapNode(3, 33, 10);
tm.add(newNode);
expect(tm.count).toBe(15);
});
it('Should count', () => {
tm.addMany([
[1, 1],
[2, 2],
[3, 3]
]);
tm.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 1);
expect(tm.count).toBe(7);
});
});
describe('TreeMultiMap operations test1', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const treeMultimap = new TreeMultiMap();
expect(treeMultimap instanceof TreeMultiMap);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
[15, 15],
[1, 1],
[8, 8],
[13, 13],
[16, 16],
[2, 2],
[6, 6],
[9, 9],
[12, 12],
[14, 14],
[4, 4],
[7, 7],
[10, 10],
[5, 5]
];
treeMultimap.addMany(idAndValues);
expect(treeMultimap.root instanceof TreeMultiMapNode);
if (treeMultimap.root) expect(treeMultimap.root.key == 11);
expect(treeMultimap.size).toBe(16);
expect(treeMultimap.count).toBe(18);
expect(treeMultimap.has(6));
expect(treeMultimap.getHeight(6)).toBe(2);
expect(treeMultimap.getDepth(6)).toBe(4);
const nodeId10 = treeMultimap.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultimap.getNode(9, node => node.value);
expect(nodeVal9?.key).toBe(9);
const nodesByCount1 = treeMultimap.getNodes(1, node => node.count);
expect(nodesByCount1.length).toBe(14);
const nodesByCount2 = treeMultimap.getNodes(2, node => node.count);
expect(nodesByCount2.length).toBe(2);
const leftMost = treeMultimap.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = treeMultimap.getNode(15);
const minNodeBySpecificNode = node15 && treeMultimap.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(15);
let subTreeSum = 0;
node15 && treeMultimap.dfs(node => (subTreeSum += node.key), 'pre', 15);
expect(subTreeSum).toBe(31);
let lesserSum = 0;
treeMultimap.lesserOrGreaterTraverse((node: TreeMultiMapNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(node15 instanceof TreeMultiMapNode);
if (node15 instanceof TreeMultiMapNode) {
const subTreeAdd = treeMultimap.dfs(node => (node.count += 1), 'pre', 15);
expect(subTreeAdd);
}
const node11 = treeMultimap.getNode(11);
expect(node11 instanceof TreeMultiMapNode);
if (node11 instanceof TreeMultiMapNode) {
const allGreaterNodesAdded = treeMultimap.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11);
expect(allGreaterNodesAdded);
}
const dfsInorderNodes = treeMultimap.dfs(node => node, 'in');
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
expect(treeMultimap.isPerfectlyBalanced()).toBe(false);
treeMultimap.perfectlyBalance();
expect(treeMultimap.isPerfectlyBalanced()).toBe(true);
expect(treeMultimap.isAVLBalanced()).toBe(true);
const bfsNodesAfterBalanced = treeMultimap.bfs(node => node);
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight(15)).toBe(2);
const removed1 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(5);
const removed4 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(5);
const removed10 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(5);
const removed15 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed5 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed13 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed3 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed8 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(4);
const removed6 = treeMultimap.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(treeMultimap.delete(6, undefined, true).length).toBe(0);
expect(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(4);
const removed7 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(4);
const removed9 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(3);
const removed14 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(2);
expect(treeMultimap.isAVLBalanced()).toBe(true);
const bfsIDs = treeMultimap.bfs(node => node.key);
expect(bfsIDs[0]).toBe(12);
expect(bfsIDs[1]).toBe(2);
expect(bfsIDs[2]).toBe(16);
const bfsNodes = treeMultimap.bfs(node => node);
expect(bfsNodes[0].key).toBe(12);
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultimap.count).toBe(8);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objTreeMultiMap = new TreeMultiMap<number, { key: number; keyA: number }>();
expect(objTreeMultiMap).toBeInstanceOf(TreeMultiMap);
objTreeMultiMap.add([11, { key: 11, keyA: 11 }]);
objTreeMultiMap.add([3, { key: 3, keyA: 3 }]);
const values: [number, { key: number; keyA: number }][] = [
[15, { key: 15, keyA: 15 }],
[1, { key: 1, keyA: 1 }],
[8, { key: 8, keyA: 8 }],
[13, { key: 13, keyA: 13 }],
[16, { key: 16, keyA: 16 }],
[2, { key: 2, keyA: 2 }],
[6, { key: 6, keyA: 6 }],
[9, { key: 9, keyA: 9 }],
[12, { key: 12, keyA: 12 }],
[14, { key: 14, keyA: 14 }],
[4, { key: 4, keyA: 4 }],
[7, { key: 7, keyA: 7 }],
[10, { key: 10, keyA: 10 }],
[5, { key: 5, keyA: 5 }]
];
objTreeMultiMap.addMany(values);
expect(objTreeMultiMap.root).toBeInstanceOf(TreeMultiMapNode);
if (objTreeMultiMap.root) expect(objTreeMultiMap.root.key).toBe(11);
expect(objTreeMultiMap.count).toBe(16);
expect(objTreeMultiMap.has(6)).toBe(true);
});
});
describe('TreeMultiMap operations test recursively1', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const treeMultimap = new TreeMultiMap<number>([], { iterationType: IterationType.RECURSIVE });
expect(treeMultimap instanceof TreeMultiMap);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
[15, 15],
[1, 1],
[8, 8],
[13, 13],
[16, 16],
[2, 2],
[6, 6],
[9, 9],
[12, 12],
[14, 14],
[4, 4],
[7, 7],
[10, 10],
[5, 5]
];
treeMultimap.addMany(idAndValues);
expect(treeMultimap.root).toBeInstanceOf(TreeMultiMapNode);
if (treeMultimap.root) expect(treeMultimap.root.key).toBe(11);
expect(treeMultimap.size).toBe(16);
expect(treeMultimap.count).toBe(18);
expect(treeMultimap.has(6));
expect(treeMultimap.getHeight(6)).toBe(2);
expect(treeMultimap.getDepth(6)).toBe(4);
const nodeId10 = treeMultimap.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultimap.getNode(9, node => node.value);
expect(nodeVal9?.key).toBe(9);
const nodesByCount1 = treeMultimap.getNodes(1, node => node.count);
expect(nodesByCount1.length).toBe(14);
const nodesByCount2 = treeMultimap.getNodes(2, node => node.count);
expect(nodesByCount2.length).toBe(2);
const leftMost = treeMultimap.getLeftMost();
expect(leftMost?.key).toBe(1);
const node15 = treeMultimap.getNode(15);
const minNodeBySpecificNode = node15 && treeMultimap.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(15);
let subTreeSum = 0;
node15 && treeMultimap.dfs(node => (subTreeSum += node.key), 'pre', 15);
expect(subTreeSum).toBe(31);
let lesserSum = 0;
expect(treeMultimap.has(9)).toBe(true);
treeMultimap.lesserOrGreaterTraverse(
node => {
lesserSum += node.key;
return node.key;
},
CP.lt,
10
);
expect(lesserSum).toBe(45);
expect(node15 instanceof TreeMultiMapNode);
if (node15 instanceof TreeMultiMapNode) {
const subTreeAdd = treeMultimap.dfs(node => (node.count += 1), 'pre', 15);
expect(subTreeAdd);
}
const node11 = treeMultimap.getNode(11);
expect(node11 instanceof TreeMultiMapNode);
if (node11 instanceof TreeMultiMapNode) {
const allGreaterNodesAdded = treeMultimap.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11);
expect(allGreaterNodesAdded);
}
const dfsInorderNodes = treeMultimap.dfs(node => node, 'in');
expect(dfsInorderNodes[0].key).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
expect(treeMultimap.isPerfectlyBalanced()).toBe(false);
treeMultimap.perfectlyBalance();
expect(treeMultimap.isPerfectlyBalanced()).toBe(true);
expect(treeMultimap.isAVLBalanced()).toBe(true);
const bfsNodesAfterBalanced = treeMultimap.bfs(node => node);
expect(bfsNodesAfterBalanced[0].key).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
const removed11 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight(15)).toBe(2);
const removed1 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(5);
const removed4 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(5);
const removed10 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(5);
const removed15 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed5 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed13 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed3 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(4);
const removed8 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(4);
const removed6 = treeMultimap.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(treeMultimap.delete(6, undefined, true).length).toBe(0);
expect(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(4);
const removed7 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(false);
expect(treeMultimap.getHeight()).toBe(4);
const removed9 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(3);
const removed14 = treeMultimap.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(treeMultimap.isAVLBalanced()).toBe(true);
expect(treeMultimap.getHeight()).toBe(2);
expect(treeMultimap.isAVLBalanced()).toBe(true);
const bfsIDs = treeMultimap.bfs(node => node.key);
expect(bfsIDs[0]).toBe(12);
expect(bfsIDs[1]).toBe(2);
expect(bfsIDs[2]).toBe(16);
const bfsNodes = treeMultimap.bfs(node => node);
expect(bfsNodes[0].key).toBe(12);
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultimap.count).toBe(8);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objTreeMultiMap = new TreeMultiMap<number, { key: number; keyA: number }>();
expect(objTreeMultiMap).toBeInstanceOf(TreeMultiMap);
objTreeMultiMap.add([11, { key: 11, keyA: 11 }]);
objTreeMultiMap.add([3, { key: 3, keyA: 3 }]);
const values: [number, { key: number; keyA: number }][] = [
[15, { key: 15, keyA: 15 }],
[1, { key: 1, keyA: 1 }],
[8, { key: 8, keyA: 8 }],
[13, { key: 13, keyA: 13 }],
[16, { key: 16, keyA: 16 }],
[2, { key: 2, keyA: 2 }],
[6, { key: 6, keyA: 6 }],
[9, { key: 9, keyA: 9 }],
[12, { key: 12, keyA: 12 }],
[14, { key: 14, keyA: 14 }],
[4, { key: 4, keyA: 4 }],
[7, { key: 7, keyA: 7 }],
[10, { key: 10, keyA: 10 }],
[5, { key: 5, keyA: 5 }]
];
objTreeMultiMap.addMany(values);
expect(objTreeMultiMap.root).toBeInstanceOf(TreeMultiMapNode);
if (objTreeMultiMap.root) expect(objTreeMultiMap.root.key).toBe(11);
expect(objTreeMultiMap.count).toBe(16);
expect(objTreeMultiMap.has(6)).toBe(true);
});
});
describe('TreeMultiMap Performance test', function () {
const treeMS = new TreeMultiMap<number, number>();
const inputSize = 1000; // Adjust input sizes as needed
beforeEach(() => {
treeMS.clear();
});
it(`Observe the time consumption of TreeMultiMap.dfs be good`, function () {
const startDFS = performance.now();
const dfs = treeMS.dfs(node => node);
isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length);
});
it('Should the time consumption of lesserOrGreaterTraverse fitting O(n log n)', function () {
const start = performance.now();
for (let i = 0; i < inputSize; i++) {
treeMS.add(i);
}
isDebug && console.log('---add', performance.now() - start);
const startL = performance.now();
treeMS.lesserOrGreaterTraverse(node => (node.count += 1), CP.lt, inputSize / 2);
isDebug && console.log('---lesserOrGreaterTraverse', performance.now() - startL);
});
it('should the clone method', () => {
function checkTreeStructure(treeMultimap: TreeMultiMap<string, number>) {
expect(treeMultimap.size).toBe(4);
expect(treeMultimap.root?.key).toBe('4');
expect(treeMultimap.root?.left?.key).toBe('1');
expect(treeMultimap.root?.left?.left?.key).toBe(NaN);
expect(treeMultimap.root?.left?.right?.key).toBe('2');
expect(treeMultimap.root?.right?.key).toBe('5');
expect(treeMultimap.root?.right?.left?.key).toBe(NaN);
expect(treeMultimap.root?.right?.right?.key).toBe(NaN);
}
const treeMultimap = new TreeMultiMap<string, number>();
treeMultimap.addMany([
['2', 2],
['4', 4],
['5', 5],
['3', 3],
['1', 1]
]);
expect(treeMultimap.size).toBe(5);
expect(treeMultimap.root?.key).toBe('3');
expect(treeMultimap.root?.left?.key).toBe('1');
expect(treeMultimap.root?.left?.left?.key).toBe(NaN);
expect(treeMultimap.root?.left?.right?.key).toBe('2');
expect(treeMultimap.root?.right?.key).toBe('4');
expect(treeMultimap.root?.right?.left?.key).toBe(NaN);
expect(treeMultimap.root?.right?.right?.key).toBe('5');
treeMultimap.delete('3');
checkTreeStructure(treeMultimap);
const cloned = treeMultimap.clone();
checkTreeStructure(cloned);
cloned.delete('1');
expect(treeMultimap.size).toBe(4);
expect(cloned.size).toBe(3);
});
});
describe('TreeMultiMap iterative methods test', () => {
let treeMM: TreeMultiMap<number, string>;
beforeEach(() => {
treeMM = new TreeMultiMap<number, string>();
treeMM.add(1, 'a', 10);
treeMM.add([2, 'b'], undefined, 10);
treeMM.add([3, 'c'], undefined, 1);
});
test('The node obtained by get Node should match the node type', () => {
const node3 = treeMM.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
expect(node3).toBeInstanceOf(RedBlackTreeNode);
});
test('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
treeMM.forEach((value, key) => {
mockCallback(value, key);
});
expect(mockCallback.mock.calls.length).toBe(3);
expect(mockCallback.mock.calls[0]).toEqual(['a', 1]);
expect(mockCallback.mock.calls[1]).toEqual(['b', 2]);
expect(mockCallback.mock.calls[2]).toEqual(['c', 3]);
});
test('filter should return a new tree with filtered elements', () => {
const filteredTree = treeMM.filter((value, key) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
[2, 'b'],
[3, 'c']
]);
});
test('map should return a new tree with modified elements', () => {
const mappedTree = treeMM.map((value, key) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
[1, '2'],
[2, '4'],
[3, '6']
]);
});
test('reduce should accumulate values', () => {
const sum = treeMM.reduce((acc, value, key) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of treeMM) {
entries.push(entry);
}
expect(entries.length).toBe(3);
expect(entries).toEqual([
[1, 'a'],
[2, 'b'],
[3, 'c']
]);
});
test('should clone work well', () => {
expect(treeMM.count).toBe(21);
const cloned = treeMM.clone();
expect(cloned.root?.left?.key).toBe(NaN);
expect(cloned.root?.right?.value).toBe('b');
});
test('should keys', () => {
const keys = treeMM.keys();
expect([...keys]).toEqual([1, 2, 3]);
});
test('should values', () => {
const values = treeMM.values();
expect([...values]).toEqual(['a', 'b', 'c']);
});
});

View file

@ -526,10 +526,10 @@ describe('UndirectedGraph tarjan', () => {
});
// test('should cuttable graph tarjan CCs return correct result', () => {
// const graph = createExampleGraph3();
// const ccs = graph.tarjan().CCs;
// expect(ccs.size).toBe(3);
// expect(getAsVerticesArrays(ccs)).toEqual([["D", "C", "B"], ["G", "F", "E"], ["A"]]);
// const graph = createExampleGraph3();
// const ccs = graph.tarjan().CCs;
// expect(ccs.size).toBe(3);
// expect(getAsVerticesArrays(ccs)).toEqual([["D", "C", "B"], ["G", "F", "E"], ["A"]]);
// });
function createExampleGraph4() {

View file

@ -14,7 +14,7 @@ import {
RedBlackTree,
SinglyLinkedList,
Stack,
TreeMultimap,
TreeMultiMap,
Trie
} from '../../src';
import { isDebugTest } from '../config';
@ -167,8 +167,8 @@ describe('conversions', () => {
]);
});
it('Entry Array to TreeMultimap', () => {
const treeMulti = new TreeMultimap<number>(entries);
it('Entry Array to TreeMultiMap', () => {
const treeMulti = new TreeMultiMap<number>(entries);
expect(treeMulti.size).toBe(9);
isDebug && treeMulti.print();
expect([...treeMulti]).toEqual([