[rb-tree] The red-black tree has been perfectly implemented and inherits from a BST. It has also passed a certain level of testing. [binary-tree] All traversal methods are compatible with sentinel nodes in the red-black tree.

This commit is contained in:
Revone 2023-11-07 19:57:35 +08:00
parent b78d92fcd1
commit 57a95e94db
3 changed files with 79 additions and 48 deletions

View file

@ -896,11 +896,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (cur !== undefined) {
ans.push(callback(cur));
if (includeNull) {
cur !== null && cur.left !== undefined && _traverse(cur.left);
cur !== null && cur.right !== undefined && _traverse(cur.right);
cur && this.isNodeOrNull(cur.left) && _traverse(cur.left);
cur && this.isNodeOrNull(cur.right) && _traverse(cur.right);
} else {
cur !== null && cur.left && _traverse(cur.left);
cur !== null && cur.right && _traverse(cur.right);
cur && cur.left && _traverse(cur.left);
cur && cur.right && _traverse(cur.right);
}
}
};
@ -914,17 +914,29 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (cur !== undefined) {
ans.push(callback(cur));
if (includeNull) {
cur !== null && cur.right !== undefined && stack.push(cur.right);
cur !== null && cur.left !== undefined && stack.push(cur.left);
cur && this.isNodeOrNull(cur.right) && stack.push(cur.right);
cur && this.isNodeOrNull(cur.left) && stack.push(cur.left);
} else {
cur !== null && cur.right && stack.push(cur.right);
cur !== null && cur.left && stack.push(cur.left);
cur && cur.right && stack.push(cur.right);
cur && cur.left && stack.push(cur.left);
}
}
}
}
return ans;
}
isNode(node: any): node is N {
return node instanceof BinaryTreeNode && node.key.toString() !== 'NaN';
}
isNIL(node: any) {
return node instanceof BinaryTreeNode && node.key.toString() === 'NaN';
}
isNodeOrNull(node: any): node is (N | null){
return this.isNode(node) || node === null;
}
dfs<C extends BTNCallback<N>>(
callback?: C,
@ -980,35 +992,35 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
switch (pattern) {
case 'in':
if (includeNull) {
if (node && node.left !== undefined) _traverse(node.left);
ans.push(callback(node));
if (node && node.right !== undefined) _traverse(node.right);
if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
this.isNodeOrNull(node) && ans.push(callback(node));
if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
} else {
if (node && node.left) _traverse(node.left);
ans.push(callback(node));
this.isNode(node) && ans.push(callback(node));
if (node && node.right) _traverse(node.right);
}
break;
case 'pre':
if (includeNull) {
ans.push(callback(node));
if (node && node.left !== undefined) _traverse(node.left);
if (node && node.right !== undefined) _traverse(node.right);
this.isNodeOrNull(node) && ans.push(callback(node));
if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
} else {
ans.push(callback(node));
this.isNode(node) && ans.push(callback(node));
if (node && node.left) _traverse(node.left);
if (node && node.right) _traverse(node.right);
}
break;
case 'post':
if (includeNull) {
if (node && node.left !== undefined) _traverse(node.left);
if (node && node.right !== undefined) _traverse(node.right);
ans.push(callback(node));
if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
this.isNodeOrNull(node) && ans.push(callback(node));
} else {
if (node && node.left) _traverse(node.left);
if (node && node.right) _traverse(node.right);
ans.push(callback(node));
this.isNode(node) && ans.push(callback(node));
}
break;
@ -1022,7 +1034,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
while (stack.length > 0) {
const cur = stack.pop();
if (cur === undefined) continue;
if (cur === undefined || this.isNIL(cur.node)) continue;
if (includeNull) {
if (cur.node === undefined) continue;
} else {
@ -1115,8 +1127,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
ans.push(callback(current));
if (includeNull) {
if (current && current.left !== undefined) queue.push(current.left);
if (current && current.right !== undefined) queue.push(current.right);
if (current && this.isNodeOrNull(current.left)) queue.push(current.left);
if (current && this.isNodeOrNull(current.right)) queue.push(current.right);
} else {
if (current.left) queue.push(current.left);
if (current.right) queue.push(current.right);
@ -1136,8 +1148,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
ans.push(callback(current));
if (includeNull) {
if (current !== null && current.left !== undefined) queue.push(current.left);
if (current !== null && current.right !== undefined) queue.push(current.right);
if (current && this.isNodeOrNull(current.left)) queue.push(current.left);
if (current && this.isNodeOrNull(current.right)) queue.push(current.right);
} else {
if (current.left) queue.push(current.left);
if (current.right) queue.push(current.right);
@ -1199,8 +1211,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (!levelsNodes[level]) levelsNodes[level] = [];
levelsNodes[level].push(callback(node));
if (includeNull) {
if (node && node.left !== undefined) _recursive(node.left, level + 1);
if (node && node.right !== undefined) _recursive(node.right, level + 1);
if (node && this.isNodeOrNull(node.left)) _recursive(node.left, level + 1);
if (node && this.isNodeOrNull(node.right)) _recursive(node.right, level + 1);
} else {
if (node && node.left) _recursive(node.left, level + 1);
if (node && node.right) _recursive(node.right, level + 1);
@ -1219,8 +1231,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
levelsNodes[level].push(callback(node));
if (includeNull) {
if (node && node.right !== undefined) stack.push([node.right, level + 1]);
if (node && node.left !== undefined) stack.push([node.left, level + 1]);
if (node && this.isNodeOrNull(node.right)) stack.push([node.right, level + 1]);
if (node && this.isNodeOrNull(node.left)) stack.push([node.left, level + 1]);
} else {
if (node && node.right) stack.push([node.right, level + 1]);
if (node && node.left) stack.push([node.left, level + 1]);

View file

@ -177,7 +177,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
return ans;
}
isRealNode(node: N | undefined): node is N {
isNode(node: N | undefined): node is N {
return node !== this.NIL && node !== undefined;
}

View file

@ -403,21 +403,14 @@ describe('RedBlackTree', () => {
expect(node225S?.parent?.key).toBe(155);
// TODO
// expect(tree.getNode(0)).toBe(undefined);
tree.add(1);
tree.add(2);
tree.add(3);
tree.add(4);
tree.add(5);
tree.add(6);
tree.add(7);
tree.add(8);
tree.add(9);
tree.add(10);
tree.add(11);
tree.add(12);
tree.add(13);
tree.add(14);
tree.add(15);
tree.add(16);
tree.add(17);
tree.add(18);
@ -425,22 +418,48 @@ describe('RedBlackTree', () => {
tree.add(110);
isDebug && tree.print();
// console.log(tree.dfs())
// console.log(tree.isBST())
expect(tree.dfs()).toEqual([
1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 22, 23, 25, 28, 33, 50, 110, 111,
155, 225
])
expect(tree.isBST()).toBe(true);
});
it('should fix the tree after insertion and deletion', () => {
for (let i = 0; i < 1000; i++) {
tree.add(getRandomInt(-100, 1000));
for (let i = 0; i < 100; i++) {
tree.add(i);
}
for (let i = 0; i < 1000; i++) {
tree.delete(getRandomInt(-100, 1000));
for (let i = 0; i < 49; i++) {
tree.delete(i);
}
for (let i = 0; i < 1000; i++) {
tree.add(getRandomInt(-100, 1000));
tree.delete(getRandomInt(-100, 1000));
}
// console.log(tree.dfs( n => n.key, "in", tree.root, IterationType.RECURSIVE))
expect(tree.size).toBe(51);
expect(tree.isBST()).toBe(true);
expect(tree.dfs( n => n.key, "in", tree.root, IterationType.ITERATIVE)).toEqual([
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
93, 94, 95, 96, 97, 98, 99
])
});
it('should fix the tree after large scale insertion and deletion', () => {
for (let i = 0; i < 10000; i++) {
tree.add(i);
}
for (let i = 0; i < 10000; i++) {
tree.delete(i);
}
expect(tree.size).toBe(0);
expect(tree.isBST()).toBe(true);
expect(tree.dfs( n => n.key, "in", tree.root, IterationType.ITERATIVE)).toEqual([])
});
});