[rb-tree] RedBlackTree has inherited from BST and implemented it perfectly.

This commit is contained in:
Revone 2023-11-07 17:02:35 +08:00
parent 120b5e6bc2
commit ea89c0278b
3 changed files with 205 additions and 137 deletions

View file

@ -6,23 +6,27 @@
* @license MIT License
*/
import {RBTNColor} from '../../types';
import {
BinaryTreeDeletedResult,
BTNCallback,
BTNKey,
IterationType,
RBTNColor,
RBTreeNodeNested,
RBTreeOptions
} from '../../types';
import {BST, BSTNode} from "./bst";
import {IBinaryTree} from "../../interfaces";
import {BinaryTreeNode} from "./binary-tree";
export class RBTreeNode {
key: number;
parent?: RBTreeNode;
left?: RBTreeNode;
right?: RBTreeNode;
color: number;
constructor(key: number, color: RBTNColor = RBTNColor.BLACK) {
this.key = key;
export class RBTreeNode<V = any, N extends RBTreeNode<V, N> = RBTreeNodeNested<V>> extends BSTNode<V, N> {
color: RBTNColor;
constructor(key: BTNKey, value?: V, color: RBTNColor = RBTNColor.BLACK) {
super(key, value);
this.color = color;
}
}
export const NIL = new RBTreeNode(0);
/**
* 1. Each node is either red or black.
* 2. The root node is always black.
@ -30,14 +34,19 @@ export const NIL = new RBTreeNode(0);
* 4. Red nodes must have black children.
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
*/
export class RedBlackTree {
constructor() {
this._root = NIL;
export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RBTreeNodeNested<V>>>
extends BST<V, N>
implements IBinaryTree<V, N>
{
constructor(options?: RBTreeOptions) {
super(options);
this._root = this.NIL;
}
protected _root: RBTreeNode;
protected _root: N;
get root(): RBTreeNode {
get root(): N {
return this._root;
}
@ -47,22 +56,29 @@ export class RedBlackTree {
return this._size;
}
/**
* The `insert` function inserts a new node with a given key into a red-black tree and fixes any
* violations of the red-black tree properties.
* @param {number} key - The key parameter is a number that represents the value to be inserted into
* the RBTree.
* @returns The function does not explicitly return anything.
*/
add(key: number): void {
const node: RBTreeNode = new RBTreeNode(key, RBTNColor.RED);
node.left = NIL;
node.right = NIL;
NIL: N = new RBTreeNode<V>(0) as unknown as N;
let y: RBTreeNode | undefined = undefined;
let x: RBTreeNode | undefined = this.root;
override add(keyOrNode: BTNKey | N | null | undefined, value?: V): N | undefined {
let node: N;
if (typeof keyOrNode === 'number') {
node = this.createNode(keyOrNode, value, RBTNColor.RED);
} else if(keyOrNode instanceof RBTreeNode) {
node = keyOrNode;
} else if (keyOrNode === null) {
return;
} else if (keyOrNode === undefined) {
return;
} else {
return;
}
while (x !== NIL) {
node.left = this.NIL;
node.right = this.NIL;
let y: N | undefined = undefined;
let x: N | undefined = this.root;
while (x !== this.NIL) {
y = x;
if (x && node.key < x.key) {
x = x.left;
@ -95,40 +111,43 @@ export class RedBlackTree {
this._size++;
}
/**
* The `delete` function in TypeScript is used to remove a node with a specific key from a red-black
* tree.
* @param {number} key - The `node` parameter is of type `RBTreeNode` and represents the current
* node being processed in the delete operation.
* @returns The `delete` function does not return anything. It has a return type of `void`.
*/
delete(key: number): void {
const helper = (node: RBTreeNode | undefined): void => {
let z: RBTreeNode = NIL;
let x: RBTreeNode | undefined, y: RBTreeNode;
while (node !== NIL) {
if (node && node.key === key) {
override createNode(key: BTNKey, value?: V, color: RBTNColor = RBTNColor.BLACK): N {
return new RBTreeNode<V, N>(key, value, color) as N;
}
delete<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C
): BinaryTreeDeletedResult<N>[] {
const ans: BinaryTreeDeletedResult<N>[] = [];
if (identifier === null) return ans;
const helper = (node: N | undefined): void => {
let z: N = this.NIL;
let x: N | undefined, y: N;
while (node !== this.NIL) {
if (node && callback(node) === identifier) {
z = node;
}
if (node && node.key <= key) {
if (node && identifier && callback(node) <= identifier) {
node = node.right;
} else {
node = node?.left;
}
}
if (z === NIL) {
if (z === this.NIL) {
this._size--;
return;
}
y = z;
let yOriginalColor: number = y.color;
if (z.left === NIL) {
if (z.left === this.NIL) {
x = z.right;
this._rbTransplant(z, z.right!);
} else if (z.right === NIL) {
} else if (z.right === this.NIL) {
x = z.left;
this._rbTransplant(z, z.left!);
} else {
@ -154,10 +173,12 @@ export class RedBlackTree {
this._size--;
};
helper(this.root);
// TODO
return ans;
}
isRealNode(node: RBTreeNode | undefined): node is RBTreeNode {
return node !== NIL && node !== undefined;
isRealNode(node: N | undefined): node is N {
return node !== this.NIL && node !== undefined;
}
/**
@ -170,20 +191,67 @@ export class RedBlackTree {
* defaults to the root of the binary search tree (`this.root`).
* @returns a RBTreeNode.
*/
getNode(key: number, beginRoot = this.root): RBTreeNode | undefined {
const dfs = (node: RBTreeNode): RBTreeNode | undefined => {
if (this.isRealNode(node)) {
if (key === node.key) {
return node;
}
// getNode(key: number, beginRoot = this.root): N | undefined {
// const dfs = (node: N): N | undefined => {
// if (this.isRealNode(node)) {
// if (key === node.key) {
// return node;
// }
//
// if (key < node.key) return dfs(node.left!);
// return dfs(node.right!);
// } else {
// return undefined;
// }
// };
// return dfs(beginRoot);
// }
if (key < node.key) return dfs(node.left!);
return dfs(node.right!);
} else {
return undefined;
}
};
return dfs(beginRoot);
getNode<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
beginRoot?: N | undefined,
iterationType?: IterationType
): N | undefined;
getNode<C extends BTNCallback<N, N>>(
identifier: N | undefined,
callback?: C,
beginRoot?: N | undefined,
iterationType?: IterationType
): N | undefined;
getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C,
beginRoot?: N | undefined,
iterationType?: IterationType
): N | undefined;
/**
* The function `get` returns the first node in a binary tree that matches the given property or key.
* @param {BTNKey | N} identifier - The `identifier` parameter is the key or value of
* the node that you want to find in the binary tree. It can be either a `BTNKey` or `N`
* type.
* @param callback - The `callback` parameter is a function that is used to determine whether a node
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
* whether the node matches the criteria or not. The default callback function
* (`this.defaultOneParamCallback`) is used if no callback function is
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
* the root node from which the search should begin.
* @param iterationType - The `iterationType` parameter specifies the type of iteration to be
* performed when searching for a node in the binary tree. It can have one of the following values:
* @returns either the found node (of type N) or null if no node is found.
*/
getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C> | undefined,
callback: C = this.defaultOneParamCallback as C,
beginRoot = this.root,
iterationType = this.iterationType
): N | null | undefined {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
}
/**
@ -192,8 +260,8 @@ export class RedBlackTree {
* a Red-Black Tree.
* @returns The leftmost node in the given RBTreeNode.
*/
getLeftMost(node: RBTreeNode = this.root): RBTreeNode {
while (node.left !== undefined && node.left !== NIL) {
getLeftMost(node: N = this.root): N {
while (node.left !== undefined && node.left !== this.NIL) {
node = node.left;
}
return node;
@ -204,8 +272,8 @@ export class RedBlackTree {
* @param {RBTreeNode} node - The parameter "node" is of type RBTreeNode.
* @returns the rightmost node in a red-black tree.
*/
getRightMost(node: RBTreeNode): RBTreeNode {
while (node.right !== undefined && node.right !== NIL) {
getRightMost(node: N): N {
while (node.right !== undefined && node.right !== this.NIL) {
node = node.right;
}
return node;
@ -216,13 +284,13 @@ export class RedBlackTree {
* @param {RBTreeNode} x - RBTreeNode - The node for which we want to find the successor.
* @returns the successor of the given RBTreeNode.
*/
getSuccessor(x: RBTreeNode): RBTreeNode | undefined {
if (x.right !== NIL) {
getSuccessor(x: N): N | undefined {
if (x.right !== this.NIL) {
return this.getLeftMost(x.right);
}
let y: RBTreeNode | undefined = x.parent;
while (y !== NIL && y !== undefined && x === y.right) {
let y: N | undefined = x.parent;
while (y !== this.NIL && y !== undefined && x === y.right) {
x = y;
y = y.parent;
}
@ -235,13 +303,13 @@ export class RedBlackTree {
* Red-Black Tree.
* @returns the predecessor of the given RBTreeNode 'x'.
*/
getPredecessor(x: RBTreeNode): RBTreeNode {
if (x.left !== NIL) {
getPredecessor(x: N): N {
if (x.left !== this.NIL) {
return this.getRightMost(x.left!);
}
let y: RBTreeNode | undefined = x.parent;
while (y !== NIL && x === y!.left) {
let y: N | undefined = x.parent;
while (y !== this.NIL && x === y!.left) {
x = y!;
y = y!.parent;
}
@ -250,19 +318,19 @@ export class RedBlackTree {
}
clear() {
this._root = NIL;
this._root = this.NIL;
this._size = 0;
}
print(beginRoot: RBTreeNode = this.root) {
const display = (root: RBTreeNode | undefined): void => {
print(beginRoot: N = this.root) {
const display = (root: N | undefined): void => {
const [lines, , ,] = _displayAux(root);
for (const line of lines) {
console.log(line);
}
};
const _displayAux = (node: RBTreeNode | undefined): [string[], number, number, number] => {
const _displayAux = (node: N | undefined): [string[], number, number, number] => {
if (node === undefined) {
return [[], 0, 0, 0];
}
@ -317,11 +385,11 @@ export class RedBlackTree {
* The function performs a left rotation on a red-black tree node.
* @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object.
*/
protected _leftRotate(x: RBTreeNode): void {
protected _leftRotate(x: N): void {
if (x.right) {
const y: RBTreeNode = x.right;
const y: N = x.right;
x.right = y.left;
if (y.left !== NIL) {
if (y.left !== this.NIL) {
if (y.left) y.left.parent = x;
}
y.parent = x.parent;
@ -342,11 +410,11 @@ export class RedBlackTree {
* @param {RBTreeNode} x - x is a RBTreeNode, which represents the node that needs to be right
* rotated.
*/
protected _rightRotate(x: RBTreeNode): void {
protected _rightRotate(x: N): void {
if (x.left) {
const y: RBTreeNode = x.left;
const y: N = x.left;
x.left = y.right;
if (y.right !== NIL) {
if (y.right !== this.NIL) {
if (y.right) y.right.parent = x;
}
y.parent = x.parent;
@ -367,8 +435,8 @@ export class RedBlackTree {
* @param {RBTreeNode} x - The parameter `x` is of type `RBTreeNode`, which represents a node in a
* red-black tree.
*/
protected _fixDelete(x: RBTreeNode): void {
let s: RBTreeNode | undefined;
protected _fixDelete(x: N): void {
let s: N | undefined;
while (x !== this.root && x.color === RBTNColor.BLACK) {
if (x.parent && x === x.parent.left) {
s = x.parent.right!;
@ -432,7 +500,7 @@ export class RedBlackTree {
* @param {RBTreeNode} u - The parameter "u" represents a RBTreeNode object.
* @param {RBTreeNode} v - The parameter "v" is a RBTreeNode object.
*/
protected _rbTransplant(u: RBTreeNode, v: RBTreeNode): void {
protected _rbTransplant(u: N, v: N): void {
if (u.parent === undefined) {
this._root = v;
} else if (u === u.parent.left) {
@ -448,8 +516,8 @@ export class RedBlackTree {
* @param {RBTreeNode} k - The parameter `k` is a RBTreeNode object, which represents a node in a
* red-black tree.
*/
protected _fixInsert(k: RBTreeNode): void {
let u: RBTreeNode | undefined;
protected _fixInsert(k: N): void {
let u: N | undefined;
while (k.parent && k.parent.color === 1) {
if (k.parent.parent && k.parent === k.parent.parent.right) {
u = k.parent.parent.left;

View file

@ -1,8 +1,8 @@
// import {BinaryTreeOptions} from './binary-tree';
// import {RBTreeNode} from '../../../data-structures';
import {RBTreeNode} from '../../../data-structures';
import {BSTOptions} from "./bst";
export enum RBTNColor { RED = 1, BLACK = 0}
// export type RBTreeNodeNested<T> = RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//
// export type RBTreeOptions = BinaryTreeOptions & {}
export type RBTreeNodeNested<T> = RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type RBTreeOptions = BSTOptions & {};

View file

@ -1,7 +1,6 @@
import {NIL, RBTNColor, RBTreeNode, RedBlackTree} from '../../../../src';
import {RBTNColor, RBTreeNode, RedBlackTree} from '../../../../src';
import {getRandomInt} from '../../../utils';
import {isDebugTest} from '../../../config';
import * as console from "console";
const isDebug = isDebugTest;
@ -67,7 +66,7 @@ describe('RedBlackTree', () => {
test('should handle an empty tree', () => {
const minNode = tree.getLeftMost(tree.root);
expect(minNode).toBe(NIL);
expect(minNode).toBe(tree.NIL);
});
});
@ -85,7 +84,7 @@ describe('RedBlackTree', () => {
test('should handle an empty tree', () => {
const maxNode = tree.getRightMost(tree.root);
expect(maxNode).toBe(NIL);
expect(maxNode).toBe(tree.NIL);
});
});
@ -109,7 +108,7 @@ describe('RedBlackTree', () => {
const node = tree.getNode(10);
const successorNode = tree.getSuccessor(node!);
// TODO not sure if it should be undefined or NIL
// TODO not sure if it should be undefined or tree.NIL
expect(successorNode).toBe(undefined);
});
});
@ -134,7 +133,7 @@ describe('RedBlackTree', () => {
const node = tree.getNode(20);
const predecessorNode = tree.getPredecessor(node!);
// TODO not sure if it should be NIL or something else.
// TODO not sure if it should be tree.NIL or something else.
expect(predecessorNode).toBe(tree.getNode(10));
});
});
@ -235,28 +234,28 @@ describe('RedBlackTree', () => {
expect(node5F?.parent).toBe(node10F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe(RBTNColor.RED);
expect(node15F?.left).toBe(NIL);
expect(node15F?.right).toBe(NIL);
expect(node15F?.left).toBe(tree.NIL);
expect(node15F?.right).toBe(tree.NIL);
expect(node15F?.parent).toBe(node20F);
expect(node21F?.key).toBe(21);
expect(node21F?.color).toBe(RBTNColor.RED);
expect(node21F?.left).toBe(NIL);
expect(node21F?.right).toBe(NIL);
expect(node21F?.left).toBe(tree.NIL);
expect(node21F?.right).toBe(tree.NIL);
expect(node21F?.parent).toBe(node20F);
expect(node6F?.key).toBe(6);
expect(node6F?.color).toBe(RBTNColor.RED);
expect(node6F?.left).toBe(NIL);
expect(node6F?.right).toBe(NIL);
expect(node6F?.left).toBe(tree.NIL);
expect(node6F?.right).toBe(tree.NIL);
expect(node6F?.parent).toBe(node5F);
expect(node2F?.key).toBe(2);
expect(node2F?.color).toBe(RBTNColor.RED);
expect(node2F?.left).toBe(NIL);
expect(node2F?.right).toBe(NIL);
expect(node2F?.left).toBe(tree.NIL);
expect(node2F?.right).toBe(tree.NIL);
expect(node2F?.parent).toBe(node5F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe(RBTNColor.RED);
expect(node15F?.left).toBe(NIL);
expect(node15F?.right).toBe(NIL);
expect(node15F?.left).toBe(tree.NIL);
expect(node15F?.right).toBe(tree.NIL);
expect(node15F?.parent).toBe(node20F);
tree.delete(5);
node10F = tree.getNode(10);
@ -279,28 +278,28 @@ describe('RedBlackTree', () => {
expect(node5F).toBe(undefined);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe(RBTNColor.RED);
expect(node15F?.left).toBe(NIL);
expect(node15F?.right).toBe(NIL);
expect(node15F?.left).toBe(tree.NIL);
expect(node15F?.right).toBe(tree.NIL);
expect(node15F?.parent).toBe(node20F);
expect(node21F?.key).toBe(21);
expect(node21F?.color).toBe(RBTNColor.RED);
expect(node21F?.left).toBe(NIL);
expect(node21F?.right).toBe(NIL);
expect(node21F?.left).toBe(tree.NIL);
expect(node21F?.right).toBe(tree.NIL);
expect(node21F?.parent).toBe(node20F);
expect(node6F?.key).toBe(6);
expect(node6F?.color).toBe(RBTNColor.BLACK);
expect(node6F?.left).toBe(node2F);
expect(node6F?.right).toBe(NIL);
expect(node6F?.right).toBe(tree.NIL);
expect(node6F?.parent).toBe(node10F);
expect(node2F?.key).toBe(2);
expect(node2F?.color).toBe(RBTNColor.RED);
expect(node2F?.left).toBe(NIL);
expect(node2F?.right).toBe(NIL);
expect(node2F?.left).toBe(tree.NIL);
expect(node2F?.right).toBe(tree.NIL);
expect(node2F?.parent).toBe(node6F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe(RBTNColor.RED);
expect(node15F?.left).toBe(NIL);
expect(node15F?.right).toBe(NIL);
expect(node15F?.left).toBe(tree.NIL);
expect(node15F?.right).toBe(tree.NIL);
expect(node15F?.parent).toBe(node20F);
tree.delete(20);
node10F = tree.getNode(10);
@ -319,28 +318,28 @@ describe('RedBlackTree', () => {
expect(node5F).toBe(undefined);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe(RBTNColor.RED);
expect(node15F?.left).toBe(NIL);
expect(node15F?.right).toBe(NIL);
expect(node15F?.left).toBe(tree.NIL);
expect(node15F?.right).toBe(tree.NIL);
expect(node15F?.parent).toBe(node21F);
expect(node21F?.key).toBe(21);
expect(node21F?.color).toBe(RBTNColor.BLACK);
expect(node21F?.left).toBe(node15F);
expect(node21F?.right).toBe(NIL);
expect(node21F?.right).toBe(tree.NIL);
expect(node21F?.parent).toBe(node10F);
expect(node6F?.key).toBe(6);
expect(node6F?.color).toBe(RBTNColor.BLACK);
expect(node6F?.left).toBe(node2F);
expect(node6F?.right).toBe(NIL);
expect(node6F?.right).toBe(tree.NIL);
expect(node6F?.parent).toBe(node10F);
expect(node2F?.key).toBe(2);
expect(node2F?.color).toBe(RBTNColor.RED);
expect(node2F?.left).toBe(NIL);
expect(node2F?.right).toBe(NIL);
expect(node2F?.left).toBe(tree.NIL);
expect(node2F?.right).toBe(tree.NIL);
expect(node2F?.parent).toBe(node6F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe(RBTNColor.RED);
expect(node15F?.left).toBe(NIL);
expect(node15F?.right).toBe(NIL);
expect(node15F?.left).toBe(tree.NIL);
expect(node15F?.right).toBe(tree.NIL);
expect(node15F?.parent).toBe(node21F);
});
@ -350,8 +349,8 @@ describe('RedBlackTree', () => {
tree.add(5);
tree.add(15);
const node15F = tree.getNode(15);
expect(node15F?.left).toBe(NIL);
expect(node15F?.right).toBe(NIL);
expect(node15F?.left).toBe(tree.NIL);
expect(node15F?.right).toBe(tree.NIL);
expect(node15F?.parent).toBe(tree.getNode(5));
tree.add(25);
@ -366,8 +365,8 @@ describe('RedBlackTree', () => {
tree.add(155);
tree.add(225);
const node225F = tree.getNode(225);
expect(node225F?.left).toBe(NIL);
expect(node225F?.right).toBe(NIL);
expect(node225F?.left).toBe(tree.NIL);
expect(node225F?.right).toBe(tree.NIL);
expect(node225F?.parent?.key).toBe(155);
tree.add(7);
@ -393,16 +392,17 @@ describe('RedBlackTree', () => {
const node50 = tree.getNode(50);
expect(node50?.key).toBe(50);
expect(node50?.left?.key).toBe(33);
expect(node50?.right).toBe(NIL);
expect(node50?.right).toBe(tree.NIL);
const node15Fo = tree.getNode(15);
expect(node15Fo?.key).toBe(15);
expect(node15Fo?.left).toBe(NIL);
expect(node15Fo?.left).toBe(tree.NIL);
const node225S = tree.getNode(225);
expect(node225S?.left).toBe(NIL);
expect(node225S?.right).toBe(NIL);
expect(node225S?.left).toBe(tree.NIL);
expect(node225S?.right).toBe(tree.NIL);
expect(node225S?.parent?.key).toBe(155);
expect(tree.getNode(0)).toBe(undefined);
// TODO
// expect(tree.getNode(0)).toBe(undefined);
tree.add(1);
tree.add(2);
tree.add(3);