mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2025-12-08 19:06:00 +00:00
325 lines
10 KiB
JavaScript
325 lines
10 KiB
JavaScript
import RedBlackTree from '../RedBlackTree';
|
|
|
|
describe('RedBlackTree', () => {
|
|
it('should always color first inserted node as black', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const firstInsertedNode = tree.insert(10);
|
|
|
|
expect(tree.isNodeColored(firstInsertedNode)).toBe(true);
|
|
expect(tree.isNodeBlack(firstInsertedNode)).toBe(true);
|
|
expect(tree.isNodeRed(firstInsertedNode)).toBe(false);
|
|
|
|
expect(tree.toString()).toBe('10');
|
|
expect(tree.root.height).toBe(0);
|
|
});
|
|
|
|
it('should always color new leaf node as red', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const firstInsertedNode = tree.insert(10);
|
|
const secondInsertedNode = tree.insert(15);
|
|
const thirdInsertedNode = tree.insert(5);
|
|
|
|
expect(tree.isNodeBlack(firstInsertedNode)).toBe(true);
|
|
expect(tree.isNodeRed(secondInsertedNode)).toBe(true);
|
|
expect(tree.isNodeRed(thirdInsertedNode)).toBe(true);
|
|
|
|
expect(tree.toString()).toBe('5,10,15');
|
|
expect(tree.root.height).toBe(1);
|
|
});
|
|
|
|
it('should balance itself', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
tree.insert(5);
|
|
tree.insert(10);
|
|
tree.insert(15);
|
|
tree.insert(20);
|
|
tree.insert(25);
|
|
tree.insert(30);
|
|
|
|
expect(tree.toString()).toBe('5,10,15,20,25,30');
|
|
expect(tree.root.height).toBe(3);
|
|
});
|
|
|
|
it('should balance itself when parent is black', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const node1 = tree.insert(10);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
|
|
const node2 = tree.insert(-10);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeRed(node2)).toBe(true);
|
|
|
|
const node3 = tree.insert(20);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeRed(node2)).toBe(true);
|
|
expect(tree.isNodeRed(node3)).toBe(true);
|
|
|
|
const node4 = tree.insert(-20);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
|
|
const node5 = tree.insert(25);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
|
|
const node6 = tree.insert(6);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node6)).toBe(true);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,6,10,20,25');
|
|
expect(tree.root.height).toBe(2);
|
|
|
|
const node7 = tree.insert(4);
|
|
|
|
expect(tree.root.left.value).toEqual(node2.value);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,4,6,10,20,25');
|
|
expect(tree.root.height).toBe(3);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeRed(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeBlack(node4)).toBe(true);
|
|
expect(tree.isNodeBlack(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
expect(tree.isNodeBlack(node6)).toBe(true);
|
|
expect(tree.isNodeRed(node7)).toBe(true);
|
|
});
|
|
|
|
it('should balance itself when uncle is red', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const node1 = tree.insert(10);
|
|
const node2 = tree.insert(-10);
|
|
const node3 = tree.insert(20);
|
|
const node4 = tree.insert(-20);
|
|
const node5 = tree.insert(6);
|
|
const node6 = tree.insert(15);
|
|
const node7 = tree.insert(25);
|
|
const node8 = tree.insert(2);
|
|
const node9 = tree.insert(8);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,2,6,8,10,15,20,25');
|
|
expect(tree.root.height).toBe(3);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeRed(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeBlack(node4)).toBe(true);
|
|
expect(tree.isNodeBlack(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node6)).toBe(true);
|
|
expect(tree.isNodeRed(node7)).toBe(true);
|
|
expect(tree.isNodeRed(node8)).toBe(true);
|
|
expect(tree.isNodeRed(node9)).toBe(true);
|
|
|
|
const node10 = tree.insert(4);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,2,4,6,8,10,15,20,25');
|
|
expect(tree.root.height).toBe(3);
|
|
|
|
expect(tree.root.value).toBe(node5.value);
|
|
|
|
expect(tree.isNodeBlack(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node1)).toBe(true);
|
|
expect(tree.isNodeRed(node2)).toBe(true);
|
|
expect(tree.isNodeRed(node10)).toBe(true);
|
|
expect(tree.isNodeRed(node6)).toBe(true);
|
|
expect(tree.isNodeRed(node7)).toBe(true);
|
|
expect(tree.isNodeBlack(node4)).toBe(true);
|
|
expect(tree.isNodeBlack(node8)).toBe(true);
|
|
expect(tree.isNodeBlack(node9)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
});
|
|
|
|
it('should do left-left rotation', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const node1 = tree.insert(10);
|
|
const node2 = tree.insert(-10);
|
|
const node3 = tree.insert(20);
|
|
const node4 = tree.insert(7);
|
|
const node5 = tree.insert(15);
|
|
|
|
expect(tree.toString()).toBe('-10,7,10,15,20');
|
|
expect(tree.root.height).toBe(2);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
|
|
const node6 = tree.insert(13);
|
|
|
|
expect(tree.toString()).toBe('-10,7,10,13,15,20');
|
|
expect(tree.root.height).toBe(2);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node6)).toBe(true);
|
|
expect(tree.isNodeRed(node3)).toBe(true);
|
|
});
|
|
|
|
it('should do left-right rotation', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const node1 = tree.insert(10);
|
|
const node2 = tree.insert(-10);
|
|
const node3 = tree.insert(20);
|
|
const node4 = tree.insert(7);
|
|
const node5 = tree.insert(15);
|
|
|
|
expect(tree.toString()).toBe('-10,7,10,15,20');
|
|
expect(tree.root.height).toBe(2);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
|
|
const node6 = tree.insert(17);
|
|
|
|
expect(tree.toString()).toBe('-10,7,10,15,17,20');
|
|
expect(tree.root.height).toBe(2);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node6)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node3)).toBe(true);
|
|
});
|
|
|
|
it('should do recoloring, left-left and left-right rotation', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const node1 = tree.insert(10);
|
|
const node2 = tree.insert(-10);
|
|
const node3 = tree.insert(20);
|
|
const node4 = tree.insert(-20);
|
|
const node5 = tree.insert(6);
|
|
const node6 = tree.insert(15);
|
|
const node7 = tree.insert(30);
|
|
const node8 = tree.insert(1);
|
|
const node9 = tree.insert(9);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,1,6,9,10,15,20,30');
|
|
expect(tree.root.height).toBe(3);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeRed(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeBlack(node4)).toBe(true);
|
|
expect(tree.isNodeBlack(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node6)).toBe(true);
|
|
expect(tree.isNodeRed(node7)).toBe(true);
|
|
expect(tree.isNodeRed(node8)).toBe(true);
|
|
expect(tree.isNodeRed(node9)).toBe(true);
|
|
|
|
tree.insert(4);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,1,4,6,9,10,15,20,30');
|
|
expect(tree.root.height).toBe(3);
|
|
});
|
|
|
|
it('should do right-left rotation', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
const node1 = tree.insert(10);
|
|
const node2 = tree.insert(-10);
|
|
const node3 = tree.insert(20);
|
|
const node4 = tree.insert(-20);
|
|
const node5 = tree.insert(6);
|
|
const node6 = tree.insert(30);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,6,10,20,30');
|
|
expect(tree.root.height).toBe(2);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node3)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node6)).toBe(true);
|
|
|
|
const node7 = tree.insert(25);
|
|
|
|
const rightNode = tree.root.right;
|
|
const rightLeftNode = rightNode.left;
|
|
const rightRightNode = rightNode.right;
|
|
|
|
expect(rightNode.value).toBe(node7.value);
|
|
expect(rightLeftNode.value).toBe(node3.value);
|
|
expect(rightRightNode.value).toBe(node6.value);
|
|
|
|
expect(tree.toString()).toBe('-20,-10,6,10,20,25,30');
|
|
expect(tree.root.height).toBe(2);
|
|
|
|
expect(tree.isNodeBlack(node1)).toBe(true);
|
|
expect(tree.isNodeBlack(node2)).toBe(true);
|
|
expect(tree.isNodeBlack(node7)).toBe(true);
|
|
expect(tree.isNodeRed(node4)).toBe(true);
|
|
expect(tree.isNodeRed(node5)).toBe(true);
|
|
expect(tree.isNodeRed(node3)).toBe(true);
|
|
expect(tree.isNodeRed(node6)).toBe(true);
|
|
});
|
|
|
|
it('should do left-left rotation with left grand-parent', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
tree.insert(20);
|
|
tree.insert(15);
|
|
tree.insert(25);
|
|
tree.insert(10);
|
|
tree.insert(5);
|
|
|
|
expect(tree.toString()).toBe('5,10,15,20,25');
|
|
expect(tree.root.height).toBe(2);
|
|
});
|
|
|
|
it('should do right-right rotation with left grand-parent', () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
tree.insert(20);
|
|
tree.insert(15);
|
|
tree.insert(25);
|
|
tree.insert(17);
|
|
tree.insert(19);
|
|
|
|
expect(tree.toString()).toBe('15,17,19,20,25');
|
|
expect(tree.root.height).toBe(2);
|
|
});
|
|
|
|
it('should throw an error when trying to remove node', () => {
|
|
const removeNodeFromRedBlackTree = () => {
|
|
const tree = new RedBlackTree();
|
|
|
|
tree.remove(1);
|
|
};
|
|
|
|
expect(removeNodeFromRedBlackTree).toThrowError();
|
|
});
|
|
});
|