mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 04:44:04 +00:00
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:
parent
18b895cb4c
commit
b099b759e8
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>> {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue