mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 04:44:04 +00:00
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:
parent
e2ab386df3
commit
465744c2ec
|
@ -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
|
||||
|
|
12
README.md
12
README.md
|
@ -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<K, V></td>
|
||||
<td>TreeMultiMap<K, V></td>
|
||||
<td>multimap<K, V></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TreeMultimap<E></td>
|
||||
<td>TreeMultiMap<E></td>
|
||||
<td>multiset<T></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;
|
||||
```
|
|
@ -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<K, V></td>
|
||||
<td>TreeMultiMap<K, V></td>
|
||||
<td>multimap<K, V></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TreeMultimap<E></td>
|
||||
<td>TreeMultiMap<E></td>
|
||||
<td>multiset<T></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
463
src/data-structures/binary-tree/tree-multi-map.ts
Normal file
463
src/data-structures/binary-tree/tree-multi-map.ts
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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> & {}
|
|
@ -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';
|
||||
|
|
8
src/types/data-structures/binary-tree/tree-multi-map.ts
Normal file
8
src/types/data-structures/binary-tree/tree-multi-map.ts
Normal 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> & {}
|
|
@ -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> & {}
|
|
@ -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___
|
||||
// / \
|
||||
|
|
|
@ -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);
|
|
@ -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', () => {
|
||||
|
|
706
test/unit/data-structures/binary-tree/tree-multi-map.test.ts
Normal file
706
test/unit/data-structures/binary-tree/tree-multi-map.test.ts
Normal 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']);
|
||||
});
|
||||
});
|
|
@ -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() {
|
||||
|
|
|
@ -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([
|
||||
|
|
Loading…
Reference in a new issue