diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 8ee5d51..241c2da 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -10,17 +10,14 @@ import {RBTNColor} from '../../types'; export class RBTreeNode { key: number; - parent: RBTreeNode; - left: RBTreeNode; - right: RBTreeNode; - color: number = RBTNColor.BLACK; + parent?: RBTreeNode; + left?: RBTreeNode; + right?: RBTreeNode; + color: number; constructor(key: number, color: RBTNColor = RBTNColor.BLACK) { this.key = key; this.color = color; - this.parent = null as unknown as RBTreeNode; - this.left = null as unknown as RBTreeNode; - this.right = null as unknown as RBTreeNode; } } @@ -62,20 +59,20 @@ export class RedBlackTree { node.left = NIL; node.right = NIL; - let y: RBTreeNode = null as unknown as RBTreeNode; - let x: RBTreeNode = this.root; + let y: RBTreeNode | undefined = undefined; + let x: RBTreeNode | undefined = this.root; while (x !== NIL) { y = x; - if (node.key < x.key) { + if (x && node.key < x.key) { x = x.left; } else { - x = x.right; + x = x?.right; } } node.parent = y; - if (y === null) { + if (y === undefined) { this._root = node; } else if (node.key < y.key) { y.left = node; @@ -83,13 +80,13 @@ export class RedBlackTree { y.right = node; } - if (node.parent === null) { + if (node.parent === undefined) { node.color = RBTNColor.BLACK; this._size++; return; } - if (node.parent.parent === null) { + if (node.parent.parent === undefined) { this._size++; return; } @@ -106,18 +103,18 @@ export class RedBlackTree { * @returns The `delete` function does not return anything. It has a return type of `void`. */ delete(key: number): void { - const helper = (node: RBTreeNode): void => { + const helper = (node: RBTreeNode | undefined): void => { let z: RBTreeNode = NIL; - let x: RBTreeNode, y: RBTreeNode; + let x: RBTreeNode | undefined, y: RBTreeNode; while (node !== NIL) { - if (node.key === key) { + if (node && node.key === key) { z = node; } - if (node.key <= key) { + if (node && node.key <= key) { node = node.right; } else { - node = node.left; + node = node?.left; } } @@ -130,37 +127,37 @@ export class RedBlackTree { let yOriginalColor: number = y.color; if (z.left === NIL) { x = z.right; - this._rbTransplant(z, z.right); + this._rbTransplant(z, z.right!); } else if (z.right === NIL) { x = z.left; - this._rbTransplant(z, z.left); + this._rbTransplant(z, z.left!); } else { y = this.getLeftMost(z.right); yOriginalColor = y.color; x = y.right; if (y.parent === z) { - x.parent = y; + x!.parent = y; } else { - this._rbTransplant(y, y.right); + this._rbTransplant(y, y.right!); y.right = z.right; - y.right.parent = y; + y.right!.parent = y; } this._rbTransplant(z, y); y.left = z.left; - y.left.parent = y; + y.left!.parent = y; y.color = z.color; } if (yOriginalColor === RBTNColor.BLACK) { - this._fixDelete(x); + this._fixDelete(x!); } this._size--; }; helper(this.root); } - isRealNode(node: RBTreeNode | null | undefined): node is RBTreeNode { - return node !== NIL && node !== null; + isRealNode(node: RBTreeNode | undefined): node is RBTreeNode { + return node !== NIL && node !== undefined; } /** @@ -173,17 +170,17 @@ export class RedBlackTree { * defaults to the root of the binary search tree (`this.root`). * @returns a RBTreeNode. */ - getNode(key: number, beginRoot = this.root): RBTreeNode { - const dfs = (node: RBTreeNode): 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; } - if (key < node.key) return dfs(node.left); - return dfs(node.right); + if (key < node.key) return dfs(node.left!); + return dfs(node.right!); } else { - return null as unknown as RBTreeNode; + return undefined; } }; return dfs(beginRoot); @@ -196,7 +193,7 @@ export class RedBlackTree { * @returns The leftmost node in the given RBTreeNode. */ getLeftMost(node: RBTreeNode = this.root): RBTreeNode { - while (node.left !== null && node.left !== NIL) { + while (node.left !== undefined && node.left !== NIL) { node = node.left; } return node; @@ -208,7 +205,7 @@ export class RedBlackTree { * @returns the rightmost node in a red-black tree. */ getRightMost(node: RBTreeNode): RBTreeNode { - while (node.right !== null && node.right !== NIL) { + while (node.right !== undefined && node.right !== NIL) { node = node.right; } return node; @@ -219,13 +216,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 { + getSuccessor(x: RBTreeNode): RBTreeNode | undefined { if (x.right !== NIL) { return this.getLeftMost(x.right); } - let y: RBTreeNode = x.parent; - while (y !== NIL && y !== null && x === y.right) { + let y: RBTreeNode | undefined = x.parent; + while (y !== NIL && y !== undefined && x === y.right) { x = y; y = y.parent; } @@ -240,16 +237,16 @@ export class RedBlackTree { */ getPredecessor(x: RBTreeNode): RBTreeNode { if (x.left !== NIL) { - return this.getRightMost(x.left); + return this.getRightMost(x.left!); } - let y: RBTreeNode = x.parent; - while (y !== NIL && x === y.left) { - x = y; - y = y.parent; + let y: RBTreeNode | undefined = x.parent; + while (y !== NIL && x === y!.left) { + x = y!; + y = y!.parent; } - return y; + return y!; } clear() { @@ -258,19 +255,19 @@ export class RedBlackTree { } print(beginRoot: RBTreeNode = this.root) { - const display = (root: RBTreeNode | null): void => { + const display = (root: RBTreeNode | undefined): 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) { + const _displayAux = (node: RBTreeNode | undefined): [string[], number, number, number] => { + if (node === undefined) { return [[], 0, 0, 0]; } - if (node.right === null && node.left === null) { + if (node.right === undefined && node.left === undefined) { const line = `${node.key}`; const width = line.length; const height = 1; @@ -278,7 +275,7 @@ export class RedBlackTree { return [[line], width, height, middle]; } - if (node.right === null) { + if (node.right === undefined) { const [lines, n, p, x] = _displayAux(node.left); const s = `${node.key}`; const u = s.length; @@ -288,7 +285,7 @@ export class RedBlackTree { return [[first_line, second_line, ...shifted_lines], n + u, p + 2, n + Math.floor(u / 2)]; } - if (node.left === null) { + if (node.left === undefined) { const [lines, n, p, u] = _displayAux(node.right); const s = `${node.key}`; const x = s.length; @@ -321,21 +318,23 @@ export class RedBlackTree { * @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object. */ protected _leftRotate(x: RBTreeNode): void { - const y: RBTreeNode = x.right; - x.right = y.left; - if (y.left !== NIL) { - y.left.parent = x; + if (x.right) { + const y: RBTreeNode = x.right; + x.right = y.left; + if (y.left !== NIL) { + if (y.left) y.left.parent = x; + } + y.parent = x.parent; + if (x.parent === undefined) { + this._root = y; + } else if (x === x.parent.left) { + x.parent.left = y; + } else { + x.parent.right = y; + } + y.left = x; + x.parent = y; } - y.parent = x.parent; - if (x.parent === null) { - this._root = y; - } else if (x === x.parent.left) { - x.parent.left = y; - } else { - x.parent.right = y; - } - y.left = x; - x.parent = y; } /** @@ -344,21 +343,23 @@ export class RedBlackTree { * rotated. */ protected _rightRotate(x: RBTreeNode): void { - const y: RBTreeNode = x.left; - x.left = y.right; - if (y.right !== NIL) { - y.right.parent = x; + if (x.left) { + const y: RBTreeNode = x.left; + x.left = y.right; + if (y.right !== NIL) { + if (y.right) y.right.parent = x; + } + y.parent = x.parent; + if (x.parent === undefined) { + this._root = y; + } else if (x === x.parent.right) { + x.parent.right = y; + } else { + x.parent.left = y; + } + y.right = x; + x.parent = y; } - y.parent = x.parent; - if (x.parent === null) { - this._root = y; - } else if (x === x.parent.right) { - x.parent.right = y; - } else { - x.parent.left = y; - } - y.right = x; - x.parent = y; } /** @@ -367,58 +368,58 @@ export class RedBlackTree { * red-black tree. */ protected _fixDelete(x: RBTreeNode): void { - let s: RBTreeNode; + let s: RBTreeNode | undefined; while (x !== this.root && x.color === RBTNColor.BLACK) { - if (x === x.parent.left) { - s = x.parent.right; + if (x.parent && x === x.parent.left) { + s = x.parent.right!; if (s.color === 1) { s.color = RBTNColor.BLACK; x.parent.color = RBTNColor.RED; this._leftRotate(x.parent); - s = x.parent.right; + s = x.parent.right!; } - if (s.left !== null && s.left.color === RBTNColor.BLACK && s.right.color === RBTNColor.BLACK) { + if (s.left !== undefined && s.left.color === RBTNColor.BLACK && s.right && s.right.color === RBTNColor.BLACK) { s.color = RBTNColor.RED; x = x.parent; } else { - if (s.right.color === RBTNColor.BLACK) { - s.left.color = RBTNColor.BLACK; + if (s.right && s.right.color === RBTNColor.BLACK) { + if (s.left) s.left.color = RBTNColor.BLACK; s.color = RBTNColor.RED; this._rightRotate(s); s = x.parent.right; } - s.color = x.parent.color; + if (s) s.color = x.parent.color; x.parent.color = RBTNColor.BLACK; - s.right.color = RBTNColor.BLACK; + if (s && s.right) s.right.color = RBTNColor.BLACK; this._leftRotate(x.parent); x = this.root; } } else { - s = x.parent.left; + s = x.parent!.left!; if (s.color === 1) { s.color = RBTNColor.BLACK; - x.parent.color = RBTNColor.RED; - this._rightRotate(x.parent); - s = x.parent.left; + x.parent!.color = RBTNColor.RED; + this._rightRotate(x.parent!); + s = x.parent!.left; } - if (s.right.color === RBTNColor.BLACK && s.right.color === RBTNColor.BLACK) { + if (s && s.right && s.right.color === RBTNColor.BLACK && s.right.color === RBTNColor.BLACK) { s.color = RBTNColor.RED; - x = x.parent; + x = x.parent!; } else { - if (s.left.color === RBTNColor.BLACK) { - s.right.color = RBTNColor.BLACK; + if (s && s.left && s.left.color === RBTNColor.BLACK) { + if (s.right) s.right.color = RBTNColor.BLACK; s.color = RBTNColor.RED; this._leftRotate(s); - s = x.parent.left; + s = x.parent!.left; } - s.color = x.parent.color; - x.parent.color = RBTNColor.BLACK; - s.left.color = RBTNColor.BLACK; - this._rightRotate(x.parent); + if (s) s.color = x.parent!.color; + x.parent!.color = RBTNColor.BLACK; + if (s && s.left) s.left.color = RBTNColor.BLACK; + this._rightRotate(x.parent!); x = this.root; } } @@ -432,7 +433,7 @@ export class RedBlackTree { * @param {RBTreeNode} v - The parameter "v" is a RBTreeNode object. */ protected _rbTransplant(u: RBTreeNode, v: RBTreeNode): void { - if (u.parent === null) { + if (u.parent === undefined) { this._root = v; } else if (u === u.parent.left) { u.parent.left = v; @@ -448,11 +449,11 @@ export class RedBlackTree { * red-black tree. */ protected _fixInsert(k: RBTreeNode): void { - let u: RBTreeNode; - while (k.parent.color === 1) { - if (k.parent === k.parent.parent.right) { + let u: RBTreeNode | undefined; + while (k.parent && k.parent.color === 1) { + if (k.parent.parent && k.parent === k.parent.parent.right) { u = k.parent.parent.left; - if (u.color === 1) { + if (u && u.color === 1) { u.color = RBTNColor.BLACK; k.parent.color = RBTNColor.BLACK; k.parent.parent.color = RBTNColor.RED; @@ -463,27 +464,27 @@ export class RedBlackTree { this._rightRotate(k); } - k.parent.color = RBTNColor.BLACK; - k.parent.parent.color = RBTNColor.RED; - this._leftRotate(k.parent.parent); + k.parent!.color = RBTNColor.BLACK; + k.parent!.parent!.color = RBTNColor.RED; + this._leftRotate(k.parent!.parent!); } } else { - u = k.parent.parent.right; + u = k.parent.parent!.right; - if (u.color === 1) { + if (u && u.color === 1) { u.color = RBTNColor.BLACK; k.parent.color = RBTNColor.BLACK; - k.parent.parent.color = RBTNColor.RED; - k = k.parent.parent; + k.parent.parent!.color = RBTNColor.RED; + k = k.parent.parent!; } else { if (k === k.parent.right) { k = k.parent; this._leftRotate(k); } - k.parent.color = RBTNColor.BLACK; - k.parent.parent.color = RBTNColor.RED; - this._rightRotate(k.parent.parent); + k.parent!.color = RBTNColor.BLACK; + k.parent!.parent!.color = RBTNColor.RED; + this._rightRotate(k.parent!.parent!); } } if (k === this.root) { diff --git a/test/unit/data-structures/binary-tree/rb-tree.test.ts b/test/unit/data-structures/binary-tree/rb-tree.test.ts index 1a2e085..2099429 100644 --- a/test/unit/data-structures/binary-tree/rb-tree.test.ts +++ b/test/unit/data-structures/binary-tree/rb-tree.test.ts @@ -1,6 +1,7 @@ import {NIL, RBTNColor, RBTreeNode, RedBlackTree} from '../../../../src'; import {getRandomInt} from '../../../utils'; import {isDebugTest} from '../../../config'; +import * as console from "console"; const isDebug = isDebugTest; @@ -20,7 +21,7 @@ describe('RedBlackTree', () => { expect(tree.getNode(10)).toBeInstanceOf(RBTreeNode); expect(tree.getNode(20)).toBeInstanceOf(RBTreeNode); expect(tree.getNode(5)).toBeInstanceOf(RBTreeNode); - expect(tree.getNode(15)).toBe(null); + expect(tree.getNode(15)).toBe(undefined); }); test('should add and find nodes with negative keys', () => { @@ -39,7 +40,7 @@ describe('RedBlackTree', () => { tree.add(5); tree.delete(20); - expect(tree.getNode(20)).toBe(null); + expect(tree.getNode(20)).toBe(undefined); }); test('should handle deleting a non-existent node', () => { @@ -48,7 +49,7 @@ describe('RedBlackTree', () => { tree.add(5); tree.delete(15); - expect(tree.getNode(15)).toBe(null); + expect(tree.getNode(15)).toBe(undefined); }); }); @@ -97,9 +98,9 @@ describe('RedBlackTree', () => { tree.add(25); const node = tree.getNode(15); - const successorNode = tree.getSuccessor(node); + const successorNode = tree.getSuccessor(node!); - expect(successorNode.key).toBe(20); + expect(successorNode?.key).toBe(20); }); test('should handle a node with no getSuccessor', () => { @@ -107,9 +108,9 @@ describe('RedBlackTree', () => { tree.add(5); const node = tree.getNode(10); - const successorNode = tree.getSuccessor(node); - // TODO not sure if it should be null or NIL - expect(successorNode).toBe(null); + const successorNode = tree.getSuccessor(node!); + // TODO not sure if it should be undefined or NIL + expect(successorNode).toBe(undefined); }); }); @@ -122,9 +123,9 @@ describe('RedBlackTree', () => { tree.add(25); const node = tree.getNode(20); - const predecessorNode = tree.getPredecessor(node); + const predecessorNode = tree.getPredecessor(node!); - expect(predecessorNode.key).toBe(15); + expect(predecessorNode?.key).toBe(15); }); test('should handle a node with no getPredecessor', () => { @@ -132,7 +133,7 @@ describe('RedBlackTree', () => { tree.add(20); const node = tree.getNode(20); - const predecessorNode = tree.getPredecessor(node); + const predecessorNode = tree.getPredecessor(node!); // TODO not sure if it should be NIL or something else. expect(predecessorNode).toBe(tree.getNode(10)); }); @@ -160,14 +161,14 @@ describe('RedBlackTree', () => { tree.add(20); tree.add(5); tree.delete(20); - expect(tree.getNode(20)).toBe(null); + expect(tree.getNode(20)).toBe(undefined); }); it('should get the successor of a node', () => { tree.add(10); tree.add(20); const node = tree.getNode(10); - const successor = tree.getSuccessor(node); + const successor = tree.getSuccessor(node!); expect(successor?.key).toBe(20); }); @@ -175,7 +176,7 @@ describe('RedBlackTree', () => { tree.add(10); tree.add(20); const node = tree.getNode(20); - const predecessor = tree.getPredecessor(node); + const predecessor = tree.getPredecessor(node!); expect(predecessor?.key).toBe(10); }); @@ -186,8 +187,8 @@ describe('RedBlackTree', () => { const node = tree.getNode(10); tree.add(15); // Verify that rotation has occurred - expect(node.left.key).toBe(5); - expect(node.right.key).toBe(20); + expect(node?.left?.key).toBe(5); + expect(node?.right?.key).toBe(20); }); it('should rotate nodes to the right', () => { @@ -197,8 +198,8 @@ describe('RedBlackTree', () => { const node = tree.getNode(20); tree.add(25); // Verify that rotation has occurred - expect(node.left.key).toBe(0); - expect(node.right.key).toBe(25); + expect(node?.left?.key).toBe(0); + expect(node?.right?.key).toBe(25); }); it('should all node attributes fully conform to the red-black tree standards.', () => { @@ -217,46 +218,46 @@ describe('RedBlackTree', () => { 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); + 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(undefined); + 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); @@ -265,42 +266,42 @@ describe('RedBlackTree', () => { 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); + 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(undefined); + 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(undefined); + 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); @@ -309,38 +310,38 @@ describe('RedBlackTree', () => { 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); + 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(undefined); + expect(node20F).toBe(undefined); + 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?.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', () => { @@ -349,9 +350,9 @@ 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.parent).toBe(tree.getNode(5)); + expect(node15F?.left).toBe(NIL); + expect(node15F?.right).toBe(NIL); + expect(node15F?.parent).toBe(tree.getNode(5)); tree.add(25); tree.add(10); @@ -365,22 +366,22 @@ 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.parent.key).toBe(155); + expect(node225F?.left).toBe(NIL); + expect(node225F?.right).toBe(NIL); + expect(node225F?.parent?.key).toBe(155); tree.add(7); const node15S = tree.getNode(15); - expect(node15S.left.key).toBe(8); - expect(node15S.right.key).toBe(28); + expect(node15S?.left?.key).toBe(8); + expect(node15S?.right?.key).toBe(28); expect(node15S).toBe(tree.root); - expect(node15S.parent).toBe(null); + expect(node15S?.parent).toBe(undefined); tree.delete(15); expect(tree.root.key).toBe(22); - expect(tree.root.parent).toBe(null); + expect(tree.root.parent).toBe(undefined); const node15T = tree.getNode(15); - expect(node15T).toBe(null); + expect(node15T).toBe(undefined); tree.add(23); tree.add(33); @@ -390,18 +391,18 @@ describe('RedBlackTree', () => { expect(nodeLM.key).toBe(1); const node50 = tree.getNode(50); - expect(node50.key).toBe(50); - expect(node50.left.key).toBe(33); - expect(node50.right).toBe(NIL); + expect(node50?.key).toBe(50); + expect(node50?.left?.key).toBe(33); + expect(node50?.right).toBe(NIL); const node15Fo = tree.getNode(15); - expect(node15Fo.key).toBe(15); - expect(node15Fo.left).toBe(NIL); + expect(node15Fo?.key).toBe(15); + expect(node15Fo?.left).toBe(NIL); const node225S = tree.getNode(225); - expect(node225S.left).toBe(NIL); - expect(node225S.right).toBe(NIL); - expect(node225S.parent.key).toBe(155); - expect(tree.getNode(0)).toBe(null); + expect(node225S?.left).toBe(NIL); + expect(node225S?.right).toBe(NIL); + expect(node225S?.parent?.key).toBe(155); + expect(tree.getNode(0)).toBe(undefined); tree.add(1); tree.add(2); tree.add(3); @@ -427,7 +428,13 @@ describe('RedBlackTree', () => { }); it('should fix the tree after insertion and deletion', () => { - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 100000; i++) { + tree.add(getRandomInt(-100, 1000)); + } + for (let i = 0; i < 100000; i++) { + tree.delete(getRandomInt(-100, 1000)); + } + for (let i = 0; i < 100000; i++) { tree.add(getRandomInt(-100, 1000)); tree.delete(getRandomInt(-100, 1000)); }