mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
[binary-tree] Let the get method call getNode instead of getNodes. [rbtree] Use rigorous testing to verify that the properties of nodes in a red-black tree adhere to the red-black tree rules after insertion and deletion.
This commit is contained in:
parent
c82190764e
commit
e9f2359365
|
@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
|
|||
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
||||
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
|
||||
|
||||
## [v1.41.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
## [v1.41.1](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
|
||||
### Changes
|
||||
|
||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "data-structure-typed",
|
||||
"version": "1.41.0",
|
||||
"version": "1.41.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "data-structure-typed",
|
||||
"version": "1.41.0",
|
||||
"version": "1.41.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/benchmark": "^2.1.3",
|
||||
|
|
|
@ -559,21 +559,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
has<C extends BTNCallback<N, BTNKey>>(
|
||||
identifier: BTNKey,
|
||||
callback?: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): boolean;
|
||||
|
||||
has<C extends BTNCallback<N, N>>(
|
||||
identifier: N | null,
|
||||
callback?: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): boolean;
|
||||
|
||||
has<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
callback: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): boolean;
|
||||
|
||||
|
@ -601,28 +601,28 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
iterationType = this.iterationType
|
||||
): boolean {
|
||||
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
|
||||
// TODO may support finding node by value equal
|
||||
|
||||
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
|
||||
}
|
||||
|
||||
getNode<C extends BTNCallback<N, BTNKey>>(
|
||||
identifier: BTNKey,
|
||||
callback?: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): N | null;
|
||||
|
||||
getNode<C extends BTNCallback<N, N>>(
|
||||
identifier: N | null,
|
||||
callback?: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): N | null;
|
||||
|
||||
getNode<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C>,
|
||||
callback: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): N | null;
|
||||
|
||||
|
@ -648,28 +648,28 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
iterationType = this.iterationType
|
||||
): N | null {
|
||||
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
|
||||
// TODO may support finding node by value equal
|
||||
|
||||
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
|
||||
}
|
||||
|
||||
get<C extends BTNCallback<N, BTNKey>>(
|
||||
identifier: BTNKey,
|
||||
callback?: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): V | undefined;
|
||||
|
||||
get<C extends BTNCallback<N, N>>(
|
||||
identifier: N | null,
|
||||
callback?: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): V | undefined;
|
||||
|
||||
get<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C>,
|
||||
callback: C,
|
||||
beginRoot?: N,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType
|
||||
): V | undefined;
|
||||
|
||||
|
@ -695,8 +695,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
iterationType = this.iterationType
|
||||
): V | undefined {
|
||||
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
|
||||
// TODO may support finding node by value equal
|
||||
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0].value ?? undefined;
|
||||
|
||||
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
import {RBTNColor} from '../../types';
|
||||
import * as console from 'console';
|
||||
|
||||
export class RBTreeNode {
|
||||
key: number;
|
||||
|
@ -16,11 +25,18 @@ export class RBTreeNode {
|
|||
}
|
||||
}
|
||||
|
||||
export const SN = new RBTreeNode(0);
|
||||
export const NIL = new RBTreeNode(0);
|
||||
|
||||
/**
|
||||
* 1. Each node is either red or black.
|
||||
* 2. The root node is always black.
|
||||
* 3. Leaf nodes are typically NIL nodes and are considered black.
|
||||
* 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 = SN;
|
||||
this._root = NIL;
|
||||
}
|
||||
|
||||
protected _root: RBTreeNode;
|
||||
|
@ -38,13 +54,13 @@ export class RedBlackTree {
|
|||
*/
|
||||
insert(key: number): void {
|
||||
const node: RBTreeNode = new RBTreeNode(key, RBTNColor.RED);
|
||||
node.left = SN;
|
||||
node.right = SN;
|
||||
node.left = NIL;
|
||||
node.right = NIL;
|
||||
|
||||
let y: RBTreeNode = null as unknown as RBTreeNode;
|
||||
let x: RBTreeNode = this.root;
|
||||
|
||||
while (x !== SN) {
|
||||
while (x !== NIL) {
|
||||
y = x;
|
||||
if (node.key < x.key) {
|
||||
x = x.left;
|
||||
|
@ -83,9 +99,9 @@ export class RedBlackTree {
|
|||
*/
|
||||
delete(key: number): void {
|
||||
const helper = (node: RBTreeNode): void => {
|
||||
let z: RBTreeNode = SN;
|
||||
let z: RBTreeNode = NIL;
|
||||
let x: RBTreeNode, y: RBTreeNode;
|
||||
while (node !== SN) {
|
||||
while (node !== NIL) {
|
||||
if (node.key === key) {
|
||||
z = node;
|
||||
}
|
||||
|
@ -97,16 +113,16 @@ export class RedBlackTree {
|
|||
}
|
||||
}
|
||||
|
||||
if (z === SN) {
|
||||
if (z === NIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
y = z;
|
||||
let yOriginalColor: number = y.color;
|
||||
if (z.left === SN) {
|
||||
if (z.left === NIL) {
|
||||
x = z.right;
|
||||
this._rbTransplant(z, z.right);
|
||||
} else if (z.right === SN) {
|
||||
} else if (z.right === NIL) {
|
||||
x = z.left;
|
||||
this._rbTransplant(z, z.left);
|
||||
} else {
|
||||
|
@ -133,8 +149,8 @@ export class RedBlackTree {
|
|||
helper(this.root);
|
||||
}
|
||||
|
||||
isRealNode(node: RBTreeNode): node is RBTreeNode {
|
||||
return node !== SN && node !== null;
|
||||
isRealNode(node: RBTreeNode | null | undefined): node is RBTreeNode {
|
||||
return node !== NIL && node !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +186,7 @@ export class RedBlackTree {
|
|||
* @returns The leftmost node in the given RBTreeNode.
|
||||
*/
|
||||
getLeftMost(node: RBTreeNode = this.root): RBTreeNode {
|
||||
while (node.left !== null && node.left !== SN) {
|
||||
while (node.left !== null && node.left !== NIL) {
|
||||
node = node.left;
|
||||
}
|
||||
return node;
|
||||
|
@ -182,7 +198,7 @@ export class RedBlackTree {
|
|||
* @returns the rightmost node in a red-black tree.
|
||||
*/
|
||||
getRightMost(node: RBTreeNode): RBTreeNode {
|
||||
while (node.right !== null && node.right !== SN) {
|
||||
while (node.right !== null && node.right !== NIL) {
|
||||
node = node.right;
|
||||
}
|
||||
return node;
|
||||
|
@ -194,12 +210,12 @@ export class RedBlackTree {
|
|||
* @returns the successor of the given RBTreeNode.
|
||||
*/
|
||||
getSuccessor(x: RBTreeNode): RBTreeNode {
|
||||
if (x.right !== SN) {
|
||||
if (x.right !== NIL) {
|
||||
return this.getLeftMost(x.right);
|
||||
}
|
||||
|
||||
let y: RBTreeNode = x.parent;
|
||||
while (y !== SN && y !== null && x === y.right) {
|
||||
while (y !== NIL && y !== null && x === y.right) {
|
||||
x = y;
|
||||
y = y.parent;
|
||||
}
|
||||
|
@ -213,12 +229,12 @@ export class RedBlackTree {
|
|||
* @returns the predecessor of the given RBTreeNode 'x'.
|
||||
*/
|
||||
getPredecessor(x: RBTreeNode): RBTreeNode {
|
||||
if (x.left !== SN) {
|
||||
if (x.left !== NIL) {
|
||||
return this.getRightMost(x.left);
|
||||
}
|
||||
|
||||
let y: RBTreeNode = x.parent;
|
||||
while (y !== SN && x === y.left) {
|
||||
while (y !== NIL && x === y.left) {
|
||||
x = y;
|
||||
y = y.parent;
|
||||
}
|
||||
|
@ -226,6 +242,65 @@ export class RedBlackTree {
|
|||
return y;
|
||||
}
|
||||
|
||||
print(beginRoot: RBTreeNode = this.root) {
|
||||
const display = (root: RBTreeNode | null): void => {
|
||||
const [lines, , ,] = _displayAux(root);
|
||||
for (const line of lines) {
|
||||
console.log(line);
|
||||
}
|
||||
};
|
||||
|
||||
const _displayAux = (node: RBTreeNode | null): [string[], number, number, number] => {
|
||||
if (node === null) {
|
||||
return [[], 0, 0, 0];
|
||||
}
|
||||
|
||||
if (node.right === null && node.left === null) {
|
||||
const line = `${node.key}`;
|
||||
const width = line.length;
|
||||
const height = 1;
|
||||
const middle = Math.floor(width / 2);
|
||||
return [[line], width, height, middle];
|
||||
}
|
||||
|
||||
if (node.right === null) {
|
||||
const [lines, n, p, x] = _displayAux(node.left);
|
||||
const s = `${node.key}`;
|
||||
const u = s.length;
|
||||
const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s;
|
||||
const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u);
|
||||
const shifted_lines = lines.map(line => line + ' '.repeat(u));
|
||||
return [[first_line, second_line, ...shifted_lines], n + u, p + 2, n + Math.floor(u / 2)];
|
||||
}
|
||||
|
||||
if (node.left === null) {
|
||||
const [lines, n, p, u] = _displayAux(node.right);
|
||||
const s = `${node.key}`;
|
||||
const x = s.length;
|
||||
const first_line = s + '_'.repeat(x) + ' '.repeat(n - x);
|
||||
const second_line = ' '.repeat(u + x) + '\\' + ' '.repeat(n - x - 1);
|
||||
const shifted_lines = lines.map(line => ' '.repeat(u) + line);
|
||||
return [[first_line, second_line, ...shifted_lines], n + x, p + 2, Math.floor(u / 2)];
|
||||
}
|
||||
|
||||
const [left, n, p, x] = _displayAux(node.left);
|
||||
const [right, m, q, y] = _displayAux(node.right);
|
||||
const s = `${node.key}`;
|
||||
const u = s.length;
|
||||
const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s + '_'.repeat(y) + ' '.repeat(m - y);
|
||||
const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u + y) + '\\' + ' '.repeat(m - y - 1);
|
||||
if (p < q) {
|
||||
left.push(...new Array(q - p).fill(' '.repeat(n)));
|
||||
} else if (q < p) {
|
||||
right.push(...new Array(p - q).fill(' '.repeat(m)));
|
||||
}
|
||||
const zipped_lines = left.map((a, i) => a + ' '.repeat(u) + right[i]);
|
||||
return [[first_line, second_line, ...zipped_lines], n + m + u, Math.max(p, q) + 2, n + Math.floor(u / 2)];
|
||||
};
|
||||
|
||||
display(beginRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function performs a left rotation on a red-black tree node.
|
||||
* @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object.
|
||||
|
@ -233,7 +308,7 @@ export class RedBlackTree {
|
|||
protected _leftRotate(x: RBTreeNode): void {
|
||||
const y: RBTreeNode = x.right;
|
||||
x.right = y.left;
|
||||
if (y.left !== SN) {
|
||||
if (y.left !== NIL) {
|
||||
y.left.parent = x;
|
||||
}
|
||||
y.parent = x.parent;
|
||||
|
@ -256,7 +331,7 @@ export class RedBlackTree {
|
|||
protected _rightRotate(x: RBTreeNode): void {
|
||||
const y: RBTreeNode = x.left;
|
||||
x.left = y.right;
|
||||
if (y.right !== SN) {
|
||||
if (y.right !== NIL) {
|
||||
y.right.parent = x;
|
||||
}
|
||||
y.parent = x.parent;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import {RBTreeNode, RedBlackTree, SN} from '../../../../src';
|
||||
import {RBTNColor, RBTreeNode, RedBlackTree, NIL} from '../../../../src';
|
||||
import {getRandomInt} from '../../../utils';
|
||||
import {isDebugTest} from '../../../config';
|
||||
|
||||
const isDebug = isDebugTest;
|
||||
|
||||
describe('RedBlackTree', () => {
|
||||
let tree: RedBlackTree;
|
||||
|
@ -63,7 +66,7 @@ describe('RedBlackTree', () => {
|
|||
|
||||
test('should handle an empty tree', () => {
|
||||
const minNode = tree.getLeftMost(tree.root);
|
||||
expect(minNode).toBe(SN);
|
||||
expect(minNode).toBe(NIL);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -81,7 +84,7 @@ describe('RedBlackTree', () => {
|
|||
|
||||
test('should handle an empty tree', () => {
|
||||
const maxNode = tree.getRightMost(tree.root);
|
||||
expect(maxNode).toBe(SN);
|
||||
expect(maxNode).toBe(NIL);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -105,7 +108,7 @@ describe('RedBlackTree', () => {
|
|||
|
||||
const node = tree.getNode(10);
|
||||
const successorNode = tree.getSuccessor(node);
|
||||
// TODO not sure if it should be null or SN
|
||||
// TODO not sure if it should be null or NIL
|
||||
expect(successorNode).toBe(null);
|
||||
});
|
||||
});
|
||||
|
@ -130,7 +133,7 @@ describe('RedBlackTree', () => {
|
|||
|
||||
const node = tree.getNode(20);
|
||||
const predecessorNode = tree.getPredecessor(node);
|
||||
// TODO not sure if it should be SN or something else.
|
||||
// TODO not sure if it should be NIL or something else.
|
||||
expect(predecessorNode).toBe(tree.getNode(10));
|
||||
});
|
||||
});
|
||||
|
@ -198,14 +201,146 @@ describe('RedBlackTree', () => {
|
|||
expect(node.right.key).toBe(25);
|
||||
});
|
||||
|
||||
it('should fix the tree after deletion', () => {
|
||||
it('should all node attributes fully conform to the red-black tree standards.', () => {
|
||||
tree.insert(10);
|
||||
tree.insert(20);
|
||||
tree.insert(5);
|
||||
tree.insert(15);
|
||||
tree.delete(15);
|
||||
// Verify that the tree is still valid
|
||||
// You can add assertions to check the Red-Black Tree properties
|
||||
tree.insert(21);
|
||||
tree.insert(6);
|
||||
tree.insert(2);
|
||||
|
||||
let node10F = tree.getNode(10);
|
||||
let node20F = tree.getNode(20);
|
||||
let node5F = tree.getNode(5);
|
||||
let node15F = tree.getNode(15);
|
||||
let node21F = tree.getNode(21);
|
||||
let node6F = tree.getNode(6);
|
||||
let node2F = tree.getNode(2);
|
||||
expect(node10F.key).toBe(10);
|
||||
expect(node10F.color).toBe(RBTNColor.BLACK);
|
||||
expect(node10F.left).toBe(node5F);
|
||||
expect(node10F.right).toBe(node20F);
|
||||
expect(node10F.parent).toBe(null);
|
||||
expect(node20F.key).toBe(20);
|
||||
expect(node20F.color).toBe(RBTNColor.BLACK);
|
||||
expect(node20F.left).toBe(node15F);
|
||||
expect(node20F.right).toBe(node21F);
|
||||
expect(node20F.parent).toBe(node10F);
|
||||
expect(node5F.key).toBe(5);
|
||||
expect(node5F.color).toBe(RBTNColor.BLACK);
|
||||
expect(node5F.left).toBe(node2F);
|
||||
expect(node5F.right).toBe(node6F);
|
||||
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.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.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.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.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.parent).toBe(node20F);
|
||||
tree.delete(5);
|
||||
node10F = tree.getNode(10);
|
||||
node20F = tree.getNode(20);
|
||||
node5F = tree.getNode(5);
|
||||
node15F = tree.getNode(15);
|
||||
node21F = tree.getNode(21);
|
||||
node6F = tree.getNode(6);
|
||||
node2F = tree.getNode(2);
|
||||
expect(node10F.key).toBe(10);
|
||||
expect(node10F.color).toBe(RBTNColor.BLACK);
|
||||
expect(node10F.left).toBe(node6F);
|
||||
expect(node10F.right).toBe(node20F);
|
||||
expect(node10F.parent).toBe(null);
|
||||
expect(node20F.key).toBe(20);
|
||||
expect(node20F.color).toBe(RBTNColor.BLACK);
|
||||
expect(node20F.left).toBe(node15F);
|
||||
expect(node20F.right).toBe(node21F);
|
||||
expect(node20F.parent).toBe(node10F);
|
||||
expect(node5F).toBe(null);
|
||||
expect(node15F.key).toBe(15);
|
||||
expect(node15F.color).toBe(RBTNColor.RED);
|
||||
expect(node15F.left).toBe(NIL);
|
||||
expect(node15F.right).toBe(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.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.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.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.parent).toBe(node20F);
|
||||
tree.delete(20);
|
||||
node10F = tree.getNode(10);
|
||||
node20F = tree.getNode(20);
|
||||
node5F = tree.getNode(5);
|
||||
node15F = tree.getNode(15);
|
||||
node21F = tree.getNode(21);
|
||||
node6F = tree.getNode(6);
|
||||
node2F = tree.getNode(2);
|
||||
expect(node10F.key).toBe(10);
|
||||
expect(node10F.color).toBe(RBTNColor.BLACK);
|
||||
expect(node10F.left).toBe(node6F);
|
||||
expect(node10F.right).toBe(node21F);
|
||||
expect(node10F.parent).toBe(null);
|
||||
expect(node20F).toBe(null);
|
||||
expect(node5F).toBe(null);
|
||||
expect(node15F.key).toBe(15);
|
||||
expect(node15F.color).toBe(RBTNColor.RED);
|
||||
expect(node15F.left).toBe(NIL);
|
||||
expect(node15F.right).toBe(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.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.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.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.parent).toBe(node21F);
|
||||
});
|
||||
|
||||
it('should fix the tree after insertion', () => {
|
||||
|
@ -214,8 +349,8 @@ describe('RedBlackTree', () => {
|
|||
tree.insert(5);
|
||||
tree.insert(15);
|
||||
const node15F = tree.getNode(15);
|
||||
expect(node15F.left).toBe(SN);
|
||||
expect(node15F.right).toBe(SN);
|
||||
expect(node15F.left).toBe(NIL);
|
||||
expect(node15F.right).toBe(NIL);
|
||||
expect(node15F.parent).toBe(tree.getNode(5));
|
||||
|
||||
tree.insert(25);
|
||||
|
@ -230,8 +365,8 @@ describe('RedBlackTree', () => {
|
|||
tree.insert(155);
|
||||
tree.insert(225);
|
||||
const node225F = tree.getNode(225);
|
||||
expect(node225F.left).toBe(SN);
|
||||
expect(node225F.right).toBe(SN);
|
||||
expect(node225F.left).toBe(NIL);
|
||||
expect(node225F.right).toBe(NIL);
|
||||
expect(node225F.parent.key).toBe(155);
|
||||
tree.insert(7);
|
||||
|
||||
|
@ -257,16 +392,38 @@ describe('RedBlackTree', () => {
|
|||
const node50 = tree.getNode(50);
|
||||
expect(node50.key).toBe(50);
|
||||
expect(node50.left.key).toBe(33);
|
||||
expect(node50.right).toBe(SN);
|
||||
expect(node50.right).toBe(NIL);
|
||||
const node15Fo = tree.getNode(15);
|
||||
|
||||
expect(node15Fo.key).toBe(15);
|
||||
expect(node15Fo.left).toBe(SN);
|
||||
expect(node15Fo.left).toBe(NIL);
|
||||
const node225S = tree.getNode(225);
|
||||
expect(node225S.left).toBe(SN);
|
||||
expect(node225S.right).toBe(SN);
|
||||
expect(node225S.left).toBe(NIL);
|
||||
expect(node225S.right).toBe(NIL);
|
||||
expect(node225S.parent.key).toBe(155);
|
||||
expect(tree.getNode(0)).toBe(null);
|
||||
tree.insert(1);
|
||||
tree.insert(2);
|
||||
tree.insert(3);
|
||||
tree.insert(4);
|
||||
tree.insert(5);
|
||||
tree.insert(6);
|
||||
tree.insert(7);
|
||||
tree.insert(8);
|
||||
tree.insert(9);
|
||||
tree.insert(10);
|
||||
tree.insert(11);
|
||||
tree.insert(12);
|
||||
tree.insert(13);
|
||||
tree.insert(14);
|
||||
tree.insert(15);
|
||||
tree.insert(16);
|
||||
tree.insert(17);
|
||||
tree.insert(18);
|
||||
tree.insert(19);
|
||||
tree.insert(110);
|
||||
|
||||
isDebug && tree.print();
|
||||
});
|
||||
|
||||
it('should fix the tree after insertion and deletion', () => {
|
||||
|
|
Loading…
Reference in a new issue