Skip to content

Allow to store references and eventually delete them #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 1, 2021
Merged
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"devDependencies": {
"@aureooms/js-compare": "2.0.0",
"@aureooms/js-itertools": "5.1.0",
"@aureooms/js-pseudo-random": "^2.0.0",
"@aureooms/js-random": "2.0.0",
"@babel/core": "7.13.14",
"@babel/preset-env": "7.13.12",
Expand Down Expand Up @@ -145,7 +146,7 @@
]
},
"cover": {
"sourceMaps": "inline",
"sourceMaps": "both",
"presets": [
"babel-preset-power-assert"
]
Expand Down
3 changes: 2 additions & 1 deletion src/deletion/delete_case0.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import delete_case1 from './delete_case1.js';
* - all other root-leaf paths have a black height of b
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const delete_case0 = (n) => {
assert(n instanceof Node);
assert(n._color === BLACK);
// If n is the root, there is nothing to do:
// - all paths go through n, and
// - n is black.
if (n.parent !== null) delete_case1(n);
return n.parent === null ? n : delete_case1(n);
};

export default delete_case0;
37 changes: 19 additions & 18 deletions src/deletion/delete_case1.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import delete_case3 from './delete_case3.js';
* - n is not the root
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const delete_case1 = (n) => {
assert(n instanceof Node);
Expand All @@ -28,25 +29,25 @@ const delete_case1 = (n) => {

if (s._color === BLACK) {
// If n's sibling is BLACK, go to case 2.
delete_case2(n);
} else {
/**
* Otherwise, prepare for and go to case 3.
*
* B B
* / \ / \
* >B R R B
* / \ / \ --> / \ / \
* - - B B >B B = =
* / \ / \ / \ / \
* = = = = - - = =
*/
n.parent._color = RED;
s._color = BLACK;
if (n === n.parent.left) rotate_left(n.parent);
else rotate_right(n.parent);
delete_case3(n);
return delete_case2(n);
}

/**
* Otherwise, prepare for and go to case 3.
*
* B *B
* / \ / \
* >B R R B
* / \ / \ --> / \ / \
* - - B B >B B = =
* / \ / \ / \ / \
* = = = = - - = =
*/
n.parent._color = RED;
s._color = BLACK;
if (n === n.parent.left) rotate_left(n.parent);
else rotate_right(n.parent);
return delete_case3(n).parent;
};

export default delete_case1;
5 changes: 3 additions & 2 deletions src/deletion/delete_case2.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import delete_case3 from './delete_case3.js';
* - n's sibling is black
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const delete_case2 = (n) => {
assert(n instanceof Node);
Expand Down Expand Up @@ -44,11 +45,11 @@ const delete_case2 = (n) => {
(s.right === null || s.right._color === BLACK)
) {
s._color = RED;
delete_case0(n.parent);
return delete_case0(n.parent);
}

// Otherwise, go to case 3.
else delete_case3(n);
return delete_case3(n);
};

export default delete_case2;
4 changes: 3 additions & 1 deletion src/deletion/delete_case3.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import delete_case4 from './delete_case4.js';
* - n's parent and n's sibling's children cannot all be black
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const delete_case3 = (n) => {
assert(n instanceof Node);
Expand Down Expand Up @@ -52,10 +53,11 @@ const delete_case3 = (n) => {
) {
s._color = RED;
n.parent._color = BLACK;
return n.parent;
}

// Otherwise, go to case 4.
else delete_case4(n);
return delete_case4(n);
};

export default delete_case3;
27 changes: 15 additions & 12 deletions src/deletion/delete_case4.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import delete_case5 from './delete_case5.js';
* - at least one of n's sibling's children is red
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const delete_case4 = (n) => {
assert(n instanceof Node);
Expand All @@ -32,18 +33,18 @@ const delete_case4 = (n) => {
// the left of the left of the parent, or right of the right, so case 5
// will rotate correctly.

/**
* ? ?
* / \ / \
* >B B >B B
* / \ / \ --> / \ / \
* - - R B - - = R
* / \ / \ / \
* = = - - = B
* / \
* - -
*/
if (n === n.parent.left && (s.right === null || s.right._color === BLACK)) {
/**
* ? ?
* / \ / \
* >B B >B B
* / \ / \ --> / \ / \
* - - R B - - = R
* / \ / \ / \
* = = - - = B
* / \
* - -
*/
s._color = RED;
s.left._color = BLACK;
rotate_right(s);
Expand All @@ -67,7 +68,9 @@ const delete_case4 = (n) => {
rotate_left(s);
}

delete_case5(n);
// TODO we could merge case 4 and 5 without too much trouble.
// It would allow to avoid checking n's direction twice.
return delete_case5(n);
};

export default delete_case4;
16 changes: 10 additions & 6 deletions src/deletion/delete_case5.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import sibling from '../family/sibling.js';
* - if n is a right child, the left child of n's sibling is red
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const delete_case5 = (n) => {
assert(n instanceof Node);
Expand All @@ -28,8 +29,9 @@ const delete_case5 = (n) => {

/**
* Increment the black height of all root-leaf paths going through n by
* swapping the colors of n's parent and n's sibling and
* rotating at n's parent. This decrements the black height of all
* root-leaft paths going through n's sibling's right child.
* root-leaf paths going through n's sibling's right child.
* We can repaint n's sibling's right child in black to fix this.
* We are done.
*
Expand All @@ -44,21 +46,23 @@ const delete_case5 = (n) => {
* - -
*/

// Swap the color of the parent and the sibling.
s._color = n.parent._color;
n.parent._color = BLACK;

if (n === n.parent.left) {
assert(s.right._color === RED);
s.right._color = BLACK;
rotate_left(n.parent);
return s;
}

// Symmetric case
else {
assert(s.left._color === RED);
s.left._color = BLACK;
rotate_right(n.parent);
}

assert(s.left._color === RED);
s.left._color = BLACK;
rotate_right(n.parent);
return s;
};

export default delete_case5;
6 changes: 4 additions & 2 deletions src/deletion/delete_no_child.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import prune from './prune.js';
* - n is not the root
*
* @param {Node} n - The node to delete.
* @return {Node} The root of the modified subtree.
*/
const delete_no_child = (n) => {
assert(n instanceof Node);
Expand All @@ -26,7 +27,7 @@ const delete_no_child = (n) => {
if (n._color !== BLACK) {
assert(n._color === RED);
prune(n);
return;
return n.parent;
}

// Mock leaf since there is no left child
Expand All @@ -39,10 +40,11 @@ const delete_no_child = (n) => {

// If n is black, deleting it reduces the black-height of every path going
// through it by 1. The leaf is black, so there are more things to fix.
delete_case1(leaf);
const subtree = delete_case1(leaf);

// Delete mocked leaf
prune(leaf);
return subtree;
};

export default delete_no_child;
2 changes: 1 addition & 1 deletion src/deletion/replace_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Node from '../types/Node.js';
const replace_node = (A, B) => {
assert(A instanceof Node);
assert(B instanceof Node);
// We never apply delete_one_child or delete_no_child on the root
// We never apply replace_node on the root
assert(A.parent !== null);

if (A === A.parent.left) A.parent.left = B;
Expand Down
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export {default as insert_case4} from './insertion/insert_case4.js';
export {default as rotate_left} from './rotate/rotate_left.js';
export {default as rotate_right} from './rotate/rotate_right.js';
export {default as search} from './search/search.js';
export {default as swap_color} from './swap/swap_color.js';
export {default as swap_left} from './swap/swap_left.js';
export {default as swap_non_adjacent} from './swap/swap_non_adjacent.js';
export {default as inordertraversal} from './traversal/inordertraversal.js';
export {default as rangetraversal} from './traversal/rangetraversal.js';
export {default as Node} from './types/Node.js';
Expand Down
9 changes: 7 additions & 2 deletions src/insertion/insert_case0.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import insert_case1 from './insert_case1.js';
* - n's children are BLACK
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const insert_case0 = (n) => {
assert(n instanceof Node);
Expand All @@ -23,8 +24,12 @@ const insert_case0 = (n) => {
* / \
* - -
*/
if (n.parent === null) n._color = BLACK;
else insert_case1(n);
if (n.parent === null) {
n._color = BLACK;
return n;
}

return insert_case1(n);
};

export default insert_case0;
5 changes: 2 additions & 3 deletions src/insertion/insert_case1.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import insert_case2 from './insert_case2.js';
* - n is not the root of the tree.
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const insert_case1 = (n) => {
assert(n instanceof Node);
Expand All @@ -28,9 +29,7 @@ const insert_case1 = (n) => {
* / \
* - -
*/
if (n.parent._color === BLACK) return;

insert_case2(n);
return n.parent._color === BLACK ? n : insert_case2(n);
};

export default insert_case1;
7 changes: 5 additions & 2 deletions src/insertion/insert_case2.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import insert_case3 from './insert_case3.js';
* - n's parent is red.
*
* @param {Node} n - The input node.
* @return {Node} The root of the modified subtree.
*/
const insert_case2 = (n) => {
assert(n instanceof Node);
Expand Down Expand Up @@ -45,8 +46,10 @@ const insert_case2 = (n) => {
u._color = BLACK;
const g = grandparent(n);
g._color = RED;
insert_case0(g);
} else insert_case3(n);
return insert_case0(g);
}

return insert_case3(n);
};

export default insert_case2;
Loading