refactor: The strategy of all binary tree data structures is to replace a node only when the same node is added.

This commit is contained in:
Revone 2023-11-25 20:40:11 +08:00
parent 18b895cb4c
commit b099b759e8
7 changed files with 186 additions and 214 deletions

View file

@ -12,8 +12,8 @@ import type {
AVLTreeOptions,
BiTreeDeleteResult,
BSTNodeKeyOrNode,
BTNodeExemplar,
BTNKey
BTNKey,
BTNodeExemplar
} from '../../types';
import { BTNCallback } from '../../types';
import { IBinaryTree } from '../../interfaces';
@ -117,7 +117,7 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
/**
* The `_swap` function swaps the key, value, and height properties between two nodes in a binary
* The `_swapProperties` function swaps the key, value, and height properties between two nodes in a binary
* tree.
* @param {BTNKey | N | undefined} srcNode - The `srcNode` parameter represents the source node that
* needs to be swapped with the destination node. It can be of type `BTNKey`, `N`, or `undefined`.
@ -126,9 +126,9 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
* @returns either the `destNode` object if both `srcNode` and `destNode` are defined, or `undefined`
* if either `srcNode` or `destNode` is undefined.
*/
protected override _swap(srcNode: BSTNodeKeyOrNode<N>, destNode: BSTNodeKeyOrNode<N>): N | undefined {
srcNode = this.ensureNotKey(srcNode);
destNode = this.ensureNotKey(destNode);
protected override _swapProperties(srcNode: BSTNodeKeyOrNode<N>, destNode: BSTNodeKeyOrNode<N>): N | undefined {
srcNode = this.ensureNode(srcNode);
destNode = this.ensureNode(destNode);
if (srcNode && destNode) {
const { key, value, height } = destNode;
@ -441,4 +441,10 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
B && this._updateHeight(B);
C && this._updateHeight(C);
}
protected _replaceNode(oldNode: N, newNode: N): N {
newNode.height = oldNode.height;
return super._replaceNode(oldNode, newNode)
}
}

View file

@ -10,9 +10,9 @@ import type {
BinaryTreeNodeNested,
BinaryTreeOptions,
BTNCallback,
BTNKey,
BTNodeEntry,
BTNodeExemplar,
BTNKey,
BTNodeKeyOrNode
} from '../../types';
import {
@ -47,7 +47,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
/**
* The parent node of the current node.
*/
parent?: N | null;
parent?: N;
/**
* Creates a new instance of BinaryTreeNode.
@ -201,8 +201,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
while (queue.size > 0) {
const cur = queue.shift()!;
if (newNode && cur.key === newNode.key) {
cur.value = newNode.value;
return;
this._replaceNode(cur, newNode);
return newNode;
}
const inserted = this._addTo(newNode, cur);
if (inserted !== undefined) return inserted;
@ -364,7 +364,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
const leftSubTreeRightMost = this.getRightMost(curr.left);
if (leftSubTreeRightMost) {
const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
orgCurrent = this._swap(curr, leftSubTreeRightMost);
orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
if (parentOfLeftSubTreeMax) {
if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost)
parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
@ -399,8 +399,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns the depth of the `distNode` relative to the `beginRoot`.
*/
getDepth(distNode: BTNodeKeyOrNode<N>, beginRoot: BTNodeKeyOrNode<N> = this.root): number {
distNode = this.ensureNotKey(distNode);
beginRoot = this.ensureNotKey(beginRoot);
distNode = this.ensureNode(distNode);
beginRoot = this.ensureNode(beginRoot);
let depth = 0;
while (distNode?.parent) {
if (distNode === beginRoot) {
@ -432,7 +432,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns the height of the binary tree.
*/
getHeight(beginRoot: BTNodeKeyOrNode<N> = this.root, iterationType = this.iterationType): number {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return -1;
if (iterationType === IterationType.RECURSIVE) {
@ -481,7 +481,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `getMinHeight` returns the minimum height of a binary tree.
*/
getMinHeight(beginRoot: BTNodeKeyOrNode<N> = this.root, iterationType = this.iterationType): number {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return -1;
if (iterationType === IterationType.RECURSIVE) {
@ -607,7 +607,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
): N[] {
if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return [];
const ans: N[] = [];
@ -809,7 +809,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
/**
* The function `ensureNotKey` returns the node corresponding to the given key if it is a valid node
* The function `ensureNode` returns the node corresponding to the given key if it is a valid node
* key, otherwise it returns the key itself.
* @param {BTNKey | N | null | undefined} key - The `key` parameter can be of type `BTNKey`, `N`,
* `null`, or `undefined`. It represents a key used to identify a node in a binary tree.
@ -819,7 +819,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns either the node corresponding to the given key if it is a valid node key, or the key
* itself if it is not a valid node key.
*/
ensureNotKey(key: BTNodeKeyOrNode<N>, iterationType = IterationType.ITERATIVE): N | null | undefined {
ensureNode(key: BTNodeKeyOrNode<N>, iterationType = IterationType.ITERATIVE): N | null | undefined {
return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
}
@ -916,7 +916,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
getPathToRoot(beginRoot: BTNodeKeyOrNode<N>, isReverse = true): N[] {
// TODO to support get path through passing key
const result: N[] = [];
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return result;
@ -953,7 +953,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
beginRoot: BTNodeKeyOrNode<N> = this.root,
iterationType = this.iterationType
): N | null | undefined {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return beginRoot;
@ -1000,7 +1000,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType = this.iterationType
): N | null | undefined {
// TODO support get right most by passing key in
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return beginRoot;
if (iterationType === IterationType.RECURSIVE) {
@ -1040,7 +1040,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
isSubtreeBST(beginRoot: BTNodeKeyOrNode<N>, iterationType = this.iterationType): boolean {
// TODO there is a bug
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return true;
if (iterationType === IterationType.RECURSIVE) {
@ -1144,7 +1144,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
if (!beginRoot) return ans;
@ -1281,7 +1281,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType: IterationType = IterationType.ITERATIVE,
includeNull = false
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return [];
const ans: ReturnType<C>[] = [];
if (iterationType === IterationType.RECURSIVE) {
@ -1422,7 +1422,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return [];
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -1523,7 +1523,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[][] {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
const levelsNodes: ReturnType<C>[][] = [];
if (!beginRoot) return levelsNodes;
@ -1578,7 +1578,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `getPredecessor` returns a value of type `N | undefined`.
*/
getPredecessor(node: BTNodeKeyOrNode<N>): N | undefined {
node = this.ensureNotKey(node);
node = this.ensureNode(node);
if (!this.isRealNode(node)) return undefined;
if (node.left) {
@ -1601,7 +1601,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* after the given node in the inorder traversal of the binary tree.
*/
getSuccessor(x?: BTNKey | N | null): N | null | undefined {
x = this.ensureNotKey(x);
x = this.ensureNode(x);
if (!x) return undefined;
if (x.right) {
@ -1639,7 +1639,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
pattern: DFSOrderPattern = 'in',
beginRoot: BTNodeKeyOrNode<N> = this.root
): ReturnType<C>[] {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (beginRoot === null) return [];
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -1847,7 +1847,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
print(beginRoot: BTNodeKeyOrNode<N> = this.root, options?: BinaryTreePrintOptions): void {
const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return;
if (opts.isShowUndefined) console.log(`U for undefined
@ -1925,9 +1925,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param {N} destNode - The destination node to swap.
* @returns {N} - The destination node after the swap.
*/
protected _swap(srcNode: BTNodeKeyOrNode<N>, destNode: BTNodeKeyOrNode<N>): N | undefined {
srcNode = this.ensureNotKey(srcNode);
destNode = this.ensureNotKey(destNode);
protected _swapProperties(srcNode: BTNodeKeyOrNode<N>, destNode: BTNodeKeyOrNode<N>): N | undefined {
srcNode = this.ensureNode(srcNode);
destNode = this.ensureNode(destNode);
if (srcNode && destNode) {
const { key, value } = destNode;
@ -1946,6 +1946,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return undefined;
}
protected _replaceNode(oldNode: N, newNode: N): N {
if (oldNode.parent) {
if (oldNode.parent.left === oldNode) {
oldNode.parent.left = newNode;
} else if (oldNode.parent.right === oldNode) {
oldNode.parent.right = newNode;
}
}
newNode.left = oldNode.left;
newNode.right = oldNode.right;
newNode.parent = oldNode.parent;
if (this.root === oldNode) {
this._root = newNode;
}
return newNode;
}
/**
* The function `_addTo` adds a new node to a binary tree if there is an available position.
* @param {N | null | undefined} newNode - The `newNode` parameter represents the node that you want to add to

View file

@ -11,10 +11,10 @@ import type {
BSTNodeNested,
BSTOptions,
BTNCallback,
BTNodeExemplar,
BTNKey,
Comparator,
BTNodePureExemplar
BTNodeExemplar,
BTNodePureExemplar,
Comparator
} from '../../types';
import { CP, IterationType } from '../../types';
import { BinaryTree, BinaryTreeNode } from './binary-tree';
@ -135,9 +135,10 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* no node was inserted, it returns `undefined`.
*/
override add(keyOrNodeOrEntry: BTNodeExemplar<V, N>): N | undefined {
if (keyOrNodeOrEntry === null) return undefined;
// TODO support node as a parameter
let inserted: N | undefined;
if (keyOrNodeOrEntry === null || keyOrNodeOrEntry === undefined) {
return undefined;
}
let newNode: N | undefined;
if (keyOrNodeOrEntry instanceof BSTNode) {
newNode = keyOrNodeOrEntry;
@ -149,64 +150,51 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
return;
} else {
newNode = this.createNode(key, value);
}
} else {
newNode = undefined;
return;
}
if (this.root === undefined) {
this._setRoot(newNode);
this._size = this.size + 1;
inserted = this.root;
} else {
let cur = this.root;
let traversing = true;
while (traversing) {
if (cur !== undefined && newNode !== undefined) {
if (this._compare(cur.key, newNode.key) === CP.eq) {
if (newNode) {
cur.value = newNode.value;
}
//Duplicates are not accepted.
traversing = false;
inserted = cur;
} else if (this._compare(cur.key, newNode.key) === CP.gt) {
// Traverse left of the node
if (cur.left === undefined) {
if (newNode) {
newNode.parent = cur;
}
//Add to the left of the current node
cur.left = newNode;
this._size = this.size + 1;
traversing = false;
inserted = cur.left;
} else {
//Traverse the left of the current node
if (cur.left) cur = cur.left;
}
} else if (this._compare(cur.key, newNode.key) === CP.lt) {
// Traverse right of the node
if (cur.right === undefined) {
if (newNode) {
newNode.parent = cur;
}
//Add to the right of the current node
cur.right = newNode;
this._size = this.size + 1;
traversing = false;
inserted = cur.right;
} else {
//Traverse the left of the current node
if (cur.right) cur = cur.right;
}
}
} else {
traversing = false;
this._size++;
return this.root;
}
let current = this.root;
while (current !== undefined) {
if (this._compare(current.key, newNode.key) === CP.eq) {
// if (current !== newNode) {
// The key value is the same but the reference is different, update the value of the existing node
this._replaceNode(current, newNode);
return newNode;
// } else {
// The key value is the same and the reference is the same, replace the entire node
// this._replaceNode(current, newNode);
// return;
// }
} else if (this._compare(current.key, newNode.key) === CP.gt) {
if (current.left === undefined) {
current.left = newNode;
newNode.parent = current;
this._size++;
return newNode;
}
current = current.left;
} else {
if (current.right === undefined) {
current.right = newNode;
newNode.parent = current;
this._size++;
return newNode;
}
current = current.right;
}
}
return inserted;
return undefined;
}
/**
@ -294,7 +282,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
const [l, r] = popped;
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const newNode = this.add(realBTNExemplars[m]);
const newNode = this.add(sorted[m]);
inserted.push(newNode);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
@ -387,7 +375,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
*/
/**
* The function `ensureNotKey` returns the node corresponding to the given key if it is a node key,
* The function `ensureNode` returns the node corresponding to the given key if it is a node key,
* otherwise it returns the key itself.
* @param {BTNKey | N | undefined} key - The `key` parameter can be of type `BTNKey`, `N`, or
* `undefined`.
@ -395,7 +383,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* type of iteration to be performed. It has a default value of `IterationType.ITERATIVE`.
* @returns either a node object (N) or undefined.
*/
override ensureNotKey(key: BSTNodeKeyOrNode<N>, iterationType = IterationType.ITERATIVE): N | undefined {
override ensureNode(key: BSTNodeKeyOrNode<N>, iterationType = IterationType.ITERATIVE): N | undefined {
return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
}
@ -429,7 +417,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
beginRoot: BSTNodeKeyOrNode<N> = this.root,
iterationType = this.iterationType
): N[] {
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return [];
const ans: N[] = [];
@ -510,7 +498,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
targetNode: BSTNodeKeyOrNode<N> = this.root,
iterationType = this.iterationType
): ReturnType<C>[] {
targetNode = this.ensureNotKey(targetNode);
targetNode = this.ensureNode(targetNode);
const ans: ReturnType<BTNCallback<N>>[] = [];
if (!targetNode) return ans;
if (!this.root) return ans;

View file

@ -10,8 +10,8 @@ import {
BiTreeDeleteResult,
BSTNodeKeyOrNode,
BTNCallback,
BTNodeExemplar,
BTNKey,
BTNodeExemplar,
IterationType,
RBTNColor,
RBTreeOptions,
@ -126,6 +126,9 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
} else if (node.key > x.key) {
x = x?.right;
} else {
if (node !== x) {
this._replaceNode(x, node)
}
return;
}
}
@ -295,7 +298,7 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
iterationType = this.iterationType
): N | null | undefined {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
beginRoot = this.ensureNotKey(beginRoot);
beginRoot = this.ensureNode(beginRoot);
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
}
@ -589,4 +592,10 @@ export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTr
}
this.root.color = RBTNColor.BLACK;
}
protected _replaceNode(oldNode: N, newNode: N): N {
newNode.color = oldNode.color;
return super._replaceNode(oldNode, newNode)
}
}

View file

@ -5,8 +5,14 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type { BSTNodeKeyOrNode, BTNodeExemplar, BTNKey, TreeMultimapNodeNested, TreeMultimapOptions } from '../../types';
import { BiTreeDeleteResult, BTNCallback, CP, FamilyPosition, IterationType, TreeMultimapNested } from '../../types';
import type {
BSTNodeKeyOrNode,
BTNKey,
BTNodeExemplar,
TreeMultimapNodeNested,
TreeMultimapOptions
} from '../../types';
import { BiTreeDeleteResult, BTNCallback, FamilyPosition, IterationType, TreeMultimapNested } from '../../types';
import { IBinaryTree } from '../../interfaces';
import { AVLTree, AVLTreeNode } from './avl-tree';
@ -95,82 +101,28 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* @returns a node (`N`) or `undefined`.
*/
override add(keyOrNodeOrEntry: BTNodeExemplar<V, N>, count = 1): N | undefined {
if (keyOrNodeOrEntry === null) return;
let inserted: N | undefined = undefined,
newNode: N | undefined;
if (keyOrNodeOrEntry instanceof TreeMultimapNode) {
newNode = this.createNode(keyOrNodeOrEntry.key, keyOrNodeOrEntry.value, keyOrNodeOrEntry.count);
} else if (keyOrNodeOrEntry === undefined) {
let newNode: N | undefined;
if (keyOrNodeOrEntry === undefined || keyOrNodeOrEntry === null) {
return;
} else if (keyOrNodeOrEntry instanceof TreeMultimapNode) {
newNode = keyOrNodeOrEntry;
} else if (this.isNodeKey(keyOrNodeOrEntry)) {
newNode = this.createNode(keyOrNodeOrEntry, undefined, count);
} else if (this.isEntry(keyOrNodeOrEntry)) {
const [key, value] = keyOrNodeOrEntry;
if (key === null || key === undefined) {
return
if (key === undefined || key === null) {
return;
} else {
newNode = this.createNode(key, value, count);
}
} else if (typeof keyOrNodeOrEntry === 'number') {
newNode = this.createNode(keyOrNodeOrEntry, undefined, 1);
} else {
return
return;
}
if (!this.root) {
this._setRoot(newNode);
this._size = this.size + 1;
if (newNode) this._count += newNode.count;
inserted = this.root;
} else {
let cur = this.root;
let traversing = true;
while (traversing) {
if (cur) {
if (newNode) {
if (this._compare(cur.key, newNode.key) === CP.eq) {
cur.value = newNode.value;
cur.count += newNode.count;
this._count += newNode.count;
traversing = false;
inserted = cur;
} else if (this._compare(cur.key, newNode.key) === CP.gt) {
// Traverse left of the node
if (cur.left === undefined) {
//Add to the left of the current node
cur.left = newNode;
this._size = this.size + 1;
this._count += newNode.count;
traversing = false;
inserted = cur.left;
} else {
//Traverse the left of the current node
if (cur.left) cur = cur.left;
}
} else if (this._compare(cur.key, newNode.key) === CP.lt) {
// Traverse right of the node
if (cur.right === undefined) {
//Add to the right of the current node
cur.right = newNode;
this._size = this.size + 1;
this._count += newNode.count;
traversing = false;
inserted = cur.right;
} else {
//Traverse the left of the current node
if (cur.right) cur = cur.right;
}
}
} else {
// TODO may need to support undefined inserted
}
} else {
traversing = false;
}
}
const orgNodeCount = newNode?.count || 0;
const inserted = super.add(newNode);
if (inserted) {
this._count += orgNodeCount;
}
if (inserted) this._balancePath(inserted);
return inserted;
}
@ -193,23 +145,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* @returns The function `addMany` returns an array of nodes (`N`) or `undefined` values.
*/
override addMany(keysOrNodesOrEntries: Iterable<BTNodeExemplar<V, N>>): (N | undefined)[] {
const inserted: (N | undefined)[] = [];
for (const keyOrNode of keysOrNodesOrEntries) {
if (keyOrNode instanceof TreeMultimapNode) {
inserted.push(this.add(keyOrNode, keyOrNode.count));
continue;
}
if (keyOrNode === undefined || keyOrNode === null) {
inserted.push(this.add(NaN, 0));
continue;
}
inserted.push(this.add(keyOrNode, 1));
}
return inserted;
return super.addMany(keysOrNodesOrEntries);
}
/**
@ -325,7 +261,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
const leftSubTreeRightMost = curr.left ? this.getRightMost(curr.left) : undefined;
if (leftSubTreeRightMost) {
const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
orgCurrent = this._swap(curr, leftSubTreeRightMost);
orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
if (parentOfLeftSubTreeMax) {
if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost) {
parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
@ -379,7 +315,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* added, or `undefined` if no node was added.
*/
protected override _addTo(newNode: N | undefined, parent: BSTNodeKeyOrNode<N>): N | undefined {
parent = this.ensureNotKey(parent);
parent = this.ensureNode(parent);
if (parent) {
if (parent.left === undefined) {
parent.left = newNode;
@ -405,7 +341,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
/**
* The `_swap` function swaps the key, value, count, and height properties between two nodes.
* The `_swapProperties` function swaps the key, value, count, and height properties between two nodes.
* @param {BTNKey | N | undefined} srcNode - The `srcNode` parameter represents the source node from
* which the values will be swapped. It can be of type `BTNKey`, `N`, or `undefined`.
* @param {BTNKey | N | undefined} destNode - The `destNode` parameter represents the destination
@ -413,9 +349,9 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* @returns either the `destNode` object if both `srcNode` and `destNode` are defined, or `undefined`
* if either `srcNode` or `destNode` is undefined.
*/
protected _swap(srcNode: BSTNodeKeyOrNode<N>, destNode: BSTNodeKeyOrNode<N>): N | undefined {
srcNode = this.ensureNotKey(srcNode);
destNode = this.ensureNotKey(destNode);
protected override _swapProperties(srcNode: BSTNodeKeyOrNode<N>, destNode: BSTNodeKeyOrNode<N>): N | undefined {
srcNode = this.ensureNode(srcNode);
destNode = this.ensureNode(destNode);
if (srcNode && destNode) {
const { key, value, count, height } = destNode;
const tempNode = this.createNode(key, value, count);
@ -437,4 +373,9 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
return undefined;
}
protected _replaceNode(oldNode: N, newNode: N): N {
newNode.count = oldNode.count + newNode.count
return super._replaceNode(oldNode, newNode);
}
}

View file

@ -5,8 +5,8 @@ import {
BinaryTreeOptions,
BiTreeDeleteResult,
BTNCallback,
BTNodeExemplar,
BTNKey,
BTNodeExemplar,
} from '../types';
export interface IBinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNodeNested<V>, TREE extends BinaryTree<V, N, TREE> = BinaryTreeNested<V, N>> {

View file

@ -4,7 +4,17 @@ import { isDebugTest } from '../../../config';
const isDebug = isDebugTest;
describe('TreeMultimap count', () => {
const tm = new TreeMultimap<number>();
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]]);
@ -13,13 +23,13 @@ describe('TreeMultimap count', () => {
})
})
describe('TreeMultimap operations test', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
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);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
@ -48,8 +58,8 @@ describe('TreeMultimap operations test', () => {
expect(treeMultimap.has(6));
expect(treeMultimap.getHeight(6)).toBe(3);
expect(treeMultimap.getDepth(6)).toBe(1);
expect(treeMultimap.getHeight(6)).toBe(4);
expect(treeMultimap.getDepth(6)).toBe(0);
const nodeId10 = treeMultimap.getNode(10);
expect(nodeId10?.key).toBe(10);
@ -66,14 +76,14 @@ describe('TreeMultimap operations test', () => {
const node15 = treeMultimap.getNode(15);
const minNodeBySpecificNode = node15 && treeMultimap.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
expect(minNodeBySpecificNode?.key).toBe(15);
let subTreeSum = 0;
node15 && treeMultimap.subTreeTraverse((node: TreeMultimapNode<number>) => (subTreeSum += node.key), 15);
expect(subTreeSum).toBe(70);
expect(subTreeSum).toBe(31);
let lesserSum = 0;
treeMultimap.lesserOrGreaterTraverse((node: TreeMultimapNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(lesserSum).toBe(21);
expect(node15 instanceof TreeMultimapNode);
if (node15 instanceof TreeMultimapNode) {
@ -230,7 +240,7 @@ describe('TreeMultimap operations test', () => {
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultimap.count).toBe(9);
expect(treeMultimap.count).toBe(4);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
@ -261,7 +271,7 @@ describe('TreeMultimap operations test', () => {
expect(objTreeMultimap.root).toBeInstanceOf(TreeMultimapNode);
if (objTreeMultimap.root) expect(objTreeMultimap.root.key).toBe(11);
if (objTreeMultimap.root) expect(objTreeMultimap.root.key).toBe(6);
expect(objTreeMultimap.count).toBe(16);
@ -269,13 +279,13 @@ describe('TreeMultimap operations test', () => {
});
});
describe('TreeMultimap operations test recursively', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
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);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
@ -297,15 +307,15 @@ describe('TreeMultimap operations test recursively', () => {
treeMultimap.addMany(idAndValues);
expect(treeMultimap.root).toBeInstanceOf(TreeMultimapNode);
if (treeMultimap.root) expect(treeMultimap.root.key == 11);
if (treeMultimap.root) expect(treeMultimap.root.key).toBe(6);
expect(treeMultimap.size).toBe(16);
expect(treeMultimap.count).toBe(18);
expect(treeMultimap.has(6));
expect(treeMultimap.getHeight(6)).toBe(3);
expect(treeMultimap.getDepth(6)).toBe(1);
expect(treeMultimap.getHeight(6)).toBe(4);
expect(treeMultimap.getDepth(6)).toBe(0);
const nodeId10 = treeMultimap.getNode(10);
expect(nodeId10?.key).toBe(10);
@ -322,14 +332,14 @@ describe('TreeMultimap operations test recursively', () => {
const node15 = treeMultimap.getNode(15);
const minNodeBySpecificNode = node15 && treeMultimap.getLeftMost(node15);
expect(minNodeBySpecificNode?.key).toBe(12);
expect(minNodeBySpecificNode?.key).toBe(15);
let subTreeSum = 0;
node15 && treeMultimap.subTreeTraverse((node: TreeMultimapNode<number>) => (subTreeSum += node.key), 15);
expect(subTreeSum).toBe(70);
expect(subTreeSum).toBe(31);
let lesserSum = 0;
treeMultimap.lesserOrGreaterTraverse((node: TreeMultimapNode<number>) => (lesserSum += node.key), CP.lt, 10);
expect(lesserSum).toBe(45);
expect(lesserSum).toBe(21);
expect(node15 instanceof TreeMultimapNode);
if (node15 instanceof TreeMultimapNode) {
@ -346,7 +356,7 @@ describe('TreeMultimap operations test recursively', () => {
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);
expect(treeMultimap.isPerfectlyBalanced()).toBe(true);
treeMultimap.perfectlyBalance();
@ -486,7 +496,7 @@ describe('TreeMultimap operations test recursively', () => {
expect(bfsNodes[1].key).toBe(2);
expect(bfsNodes[2].key).toBe(16);
expect(treeMultimap.count).toBe(9);
expect(treeMultimap.count).toBe(4);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
@ -517,7 +527,7 @@ describe('TreeMultimap operations test recursively', () => {
expect(objTreeMultimap.root).toBeInstanceOf(TreeMultimapNode);
if (objTreeMultimap.root) expect(objTreeMultimap.root.key).toBe(11);
if (objTreeMultimap.root) expect(objTreeMultimap.root.key).toBe(6);
expect(objTreeMultimap.count).toBe(16);