diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 887f83a..c5892e1 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -34,14 +34,14 @@ export class RedBlackTreeNode = RedBla /** * 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. + * 3. Leaf nodes are typically Sentinel 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 = RedBlackTreeNode>> extends BST implements IBinaryTree { - NIL: N = new RedBlackTreeNode(NaN) as unknown as N; + Sentinel: N = new RedBlackTreeNode(NaN) as unknown as N; /** * The constructor function initializes a Red-Black Tree with an optional set of options. @@ -50,7 +50,7 @@ export class RedBlackTree = RedBlackTr */ constructor(options?: RBTreeOptions) { super(options); - this._root = this.NIL; + this._root = this.Sentinel; } protected _root: N; @@ -95,13 +95,13 @@ export class RedBlackTree = RedBlackTr return; } - node.left = this.NIL; - node.right = this.NIL; + node.left = this.Sentinel; + node.right = this.Sentinel; let y: N | undefined = undefined; let x: N | undefined = this.root; - while (x !== this.NIL) { + while (x !== this.Sentinel) { y = x; if (x) { if (node.key < x.key) { @@ -170,9 +170,9 @@ export class RedBlackTree = RedBlackTr const ans: BiTreeDeleteResult[] = []; if (identifier === null) return ans; const helper = (node: N | undefined): void => { - let z: N = this.NIL; + let z: N = this.Sentinel; let x: N | undefined, y: N; - while (node !== this.NIL) { + while (node !== this.Sentinel) { if (node && callback(node) === identifier) { z = node; } @@ -184,17 +184,17 @@ export class RedBlackTree = RedBlackTr } } - if (z === this.NIL) { + if (z === this.Sentinel) { this._size--; return; } y = z; let yOriginalColor: number = y.color; - if (z.left === this.NIL) { + if (z.left === this.Sentinel) { x = z.right; this._rbTransplant(z, z.right!); - } else if (z.right === this.NIL) { + } else if (z.right === this.Sentinel) { x = z.left; this._rbTransplant(z, z.left!); } else { @@ -225,7 +225,7 @@ export class RedBlackTree = RedBlackTr } override isRealNode(node: N | undefined): node is N { - return node !== this.NIL && node !== undefined; + return node !== this.Sentinel && node !== undefined; } getNode>( @@ -300,12 +300,12 @@ export class RedBlackTree = RedBlackTr * @returns the successor of the given RedBlackTreeNode. */ override getSuccessor(x: N): N | undefined { - if (x.right !== this.NIL) { + if (x.right !== this.Sentinel) { return this.getLeftMost(x.right) ?? undefined; } let y: N | undefined = x.parent; - while (y !== this.NIL && y !== undefined && x === y.right) { + while (y !== this.Sentinel && y !== undefined && x === y.right) { x = y; y = y.parent; } @@ -327,12 +327,12 @@ export class RedBlackTree = RedBlackTr * @returns the predecessor of the given RedBlackTreeNode 'x'. */ override getPredecessor(x: N): N { - if (x.left !== this.NIL) { + if (x.left !== this.Sentinel) { return this.getRightMost(x.left!)!; } let y: N | undefined = x.parent; - while (y !== this.NIL && x === y!.left) { + while (y !== this.Sentinel && x === y!.left) { x = y!; y = y!.parent; } @@ -341,7 +341,7 @@ export class RedBlackTree = RedBlackTr } override clear() { - this._root = this.NIL; + this._root = this.Sentinel; this._size = 0; } @@ -368,7 +368,7 @@ export class RedBlackTree = RedBlackTr if (x.right) { const y: N = x.right; x.right = y.left; - if (y.left !== this.NIL) { + if (y.left !== this.Sentinel) { if (y.left) y.left.parent = x; } y.parent = x.parent; @@ -401,7 +401,7 @@ export class RedBlackTree = RedBlackTr if (x.left) { const y: N = x.left; x.left = y.right; - if (y.right !== this.NIL) { + if (y.right !== this.Sentinel) { if (y.right) y.right.parent = x; } y.parent = x.parent; 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 a644bdf..88e78ce 100644 --- a/test/unit/data-structures/binary-tree/rb-tree.test.ts +++ b/test/unit/data-structures/binary-tree/rb-tree.test.ts @@ -67,7 +67,7 @@ describe('RedBlackTree', () => { it('should handle an empty tree', () => { const minNode = tree.getLeftMost(tree.root); - expect(minNode).toBe(tree.NIL); + expect(minNode).toBe(tree.Sentinel); }); }); @@ -85,7 +85,7 @@ describe('RedBlackTree', () => { it('should handle an empty tree', () => { const maxNode = tree.getRightMost(tree.root); - expect(maxNode).toBe(tree.NIL); + expect(maxNode).toBe(tree.Sentinel); }); }); @@ -109,7 +109,7 @@ describe('RedBlackTree', () => { const node = tree.getNode(10); const successorNode = tree.getSuccessor(node!); - // TODO not sure if it should be undefined or tree.NIL + // TODO not sure if it should be undefined or tree.Sentinel expect(successorNode).toBe(undefined); }); }); @@ -134,7 +134,7 @@ describe('RedBlackTree', () => { const node = tree.getNode(20); const predecessorNode = tree.getPredecessor(node!); - // TODO not sure if it should be tree.NIL or something else. + // TODO not sure if it should be tree.Sentinel or something else. expect(predecessorNode).toBe(tree.getNode(10)); }); }); @@ -235,28 +235,28 @@ describe('RedBlackTree', () => { expect(node5F?.parent).toBe(node10F); expect(node15F?.key).toBe(15); expect(node15F?.color).toBe(RBTNColor.RED); - expect(node15F?.left).toBe(tree.NIL); - expect(node15F?.right).toBe(tree.NIL); + expect(node15F?.left).toBe(tree.Sentinel); + expect(node15F?.right).toBe(tree.Sentinel); expect(node15F?.parent).toBe(node20F); expect(node21F?.key).toBe(21); expect(node21F?.color).toBe(RBTNColor.RED); - expect(node21F?.left).toBe(tree.NIL); - expect(node21F?.right).toBe(tree.NIL); + expect(node21F?.left).toBe(tree.Sentinel); + expect(node21F?.right).toBe(tree.Sentinel); expect(node21F?.parent).toBe(node20F); expect(node6F?.key).toBe(6); expect(node6F?.color).toBe(RBTNColor.RED); - expect(node6F?.left).toBe(tree.NIL); - expect(node6F?.right).toBe(tree.NIL); + expect(node6F?.left).toBe(tree.Sentinel); + expect(node6F?.right).toBe(tree.Sentinel); expect(node6F?.parent).toBe(node5F); expect(node2F?.key).toBe(2); expect(node2F?.color).toBe(RBTNColor.RED); - expect(node2F?.left).toBe(tree.NIL); - expect(node2F?.right).toBe(tree.NIL); + expect(node2F?.left).toBe(tree.Sentinel); + expect(node2F?.right).toBe(tree.Sentinel); expect(node2F?.parent).toBe(node5F); expect(node15F?.key).toBe(15); expect(node15F?.color).toBe(RBTNColor.RED); - expect(node15F?.left).toBe(tree.NIL); - expect(node15F?.right).toBe(tree.NIL); + expect(node15F?.left).toBe(tree.Sentinel); + expect(node15F?.right).toBe(tree.Sentinel); expect(node15F?.parent).toBe(node20F); tree.delete(5); node10F = tree.getNode(10); @@ -279,28 +279,28 @@ describe('RedBlackTree', () => { expect(node5F).toBe(undefined); expect(node15F?.key).toBe(15); expect(node15F?.color).toBe(RBTNColor.RED); - expect(node15F?.left).toBe(tree.NIL); - expect(node15F?.right).toBe(tree.NIL); + expect(node15F?.left).toBe(tree.Sentinel); + expect(node15F?.right).toBe(tree.Sentinel); expect(node15F?.parent).toBe(node20F); expect(node21F?.key).toBe(21); expect(node21F?.color).toBe(RBTNColor.RED); - expect(node21F?.left).toBe(tree.NIL); - expect(node21F?.right).toBe(tree.NIL); + expect(node21F?.left).toBe(tree.Sentinel); + expect(node21F?.right).toBe(tree.Sentinel); 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(tree.NIL); + expect(node6F?.right).toBe(tree.Sentinel); expect(node6F?.parent).toBe(node10F); expect(node2F?.key).toBe(2); expect(node2F?.color).toBe(RBTNColor.RED); - expect(node2F?.left).toBe(tree.NIL); - expect(node2F?.right).toBe(tree.NIL); + expect(node2F?.left).toBe(tree.Sentinel); + expect(node2F?.right).toBe(tree.Sentinel); expect(node2F?.parent).toBe(node6F); expect(node15F?.key).toBe(15); expect(node15F?.color).toBe(RBTNColor.RED); - expect(node15F?.left).toBe(tree.NIL); - expect(node15F?.right).toBe(tree.NIL); + expect(node15F?.left).toBe(tree.Sentinel); + expect(node15F?.right).toBe(tree.Sentinel); expect(node15F?.parent).toBe(node20F); tree.delete(20); node10F = tree.getNode(10); @@ -319,28 +319,28 @@ describe('RedBlackTree', () => { expect(node5F).toBe(undefined); expect(node15F?.key).toBe(15); expect(node15F?.color).toBe(RBTNColor.RED); - expect(node15F?.left).toBe(tree.NIL); - expect(node15F?.right).toBe(tree.NIL); + expect(node15F?.left).toBe(tree.Sentinel); + expect(node15F?.right).toBe(tree.Sentinel); 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(tree.NIL); + expect(node21F?.right).toBe(tree.Sentinel); 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(tree.NIL); + expect(node6F?.right).toBe(tree.Sentinel); expect(node6F?.parent).toBe(node10F); expect(node2F?.key).toBe(2); expect(node2F?.color).toBe(RBTNColor.RED); - expect(node2F?.left).toBe(tree.NIL); - expect(node2F?.right).toBe(tree.NIL); + expect(node2F?.left).toBe(tree.Sentinel); + expect(node2F?.right).toBe(tree.Sentinel); expect(node2F?.parent).toBe(node6F); expect(node15F?.key).toBe(15); expect(node15F?.color).toBe(RBTNColor.RED); - expect(node15F?.left).toBe(tree.NIL); - expect(node15F?.right).toBe(tree.NIL); + expect(node15F?.left).toBe(tree.Sentinel); + expect(node15F?.right).toBe(tree.Sentinel); expect(node15F?.parent).toBe(node21F); }); @@ -350,8 +350,8 @@ describe('RedBlackTree', () => { tree.add(5); tree.add(15); const node15F = tree.getNode(15); - expect(node15F?.left).toBe(tree.NIL); - expect(node15F?.right).toBe(tree.NIL); + expect(node15F?.left).toBe(tree.Sentinel); + expect(node15F?.right).toBe(tree.Sentinel); expect(node15F?.parent).toBe(tree.getNode(5)); tree.add(25); @@ -366,8 +366,8 @@ describe('RedBlackTree', () => { tree.add(155); tree.add(225); const node225F = tree.getNode(225); - expect(node225F?.left).toBe(tree.NIL); - expect(node225F?.right).toBe(tree.NIL); + expect(node225F?.left).toBe(tree.Sentinel); + expect(node225F?.right).toBe(tree.Sentinel); expect(node225F?.parent?.key).toBe(155); tree.add(7); @@ -393,14 +393,14 @@ describe('RedBlackTree', () => { const node50 = tree.getNode(50); expect(node50?.key).toBe(50); expect(node50?.left?.key).toBe(33); - expect(node50?.right).toBe(tree.NIL); + expect(node50?.right).toBe(tree.Sentinel); const node15Fo = tree.getNode(15); expect(node15Fo?.key).toBe(15); - expect(node15Fo?.left).toBe(tree.NIL); + expect(node15Fo?.left).toBe(tree.Sentinel); const node225S = tree.getNode(225); - expect(node225S?.left).toBe(tree.NIL); - expect(node225S?.right).toBe(tree.NIL); + expect(node225S?.left).toBe(tree.Sentinel); + expect(node225S?.right).toBe(tree.Sentinel); expect(node225S?.parent?.key).toBe(155); // TODO // expect(tree.getNode(0)).toBe(undefined); @@ -465,7 +465,7 @@ describe('RedBlackTree', () => { tree.delete(getRandomInt(-100, 1000)); } - // TODO there is a bug when dfs the tree with NIL node + // TODO there is a bug when dfs the tree with Sentinel node // expect(tree.isBST()).toBe(true); }); const { HUNDRED_THOUSAND } = magnitude;