Skip to content

Remove usage of explicit leaves #108

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 21 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f5949c8
:construction: progress: First draft without explicit leaves.
make-github-pseudonymous-again Mar 31, 2021
6d8bd39
:bicyclist: perf(delete_one_child): Hoist red input case.
make-github-pseudonymous-again Mar 31, 2021
9d8349e
:wrench: config(cover): Fix coverage report generation.
make-github-pseudonymous-again Mar 31, 2021
eaa7d87
:recycle: refactor(delete): Split "no-child" and "exactly-one-child" …
make-github-pseudonymous-again Mar 31, 2021
7ccb61f
:recycle: refactor(delete_one_child): Remove impossible execution paths.
make-github-pseudonymous-again Mar 31, 2021
2517863
:truck: refactor: Rename prune_subtree to prune.
make-github-pseudonymous-again Mar 31, 2021
e6574c2
:sparkles: feat: Export delete_no_child and prune.
make-github-pseudonymous-again Mar 31, 2021
64aaedc
:recycle: refactor(delete_case1): Do not allow Leaf input.
make-github-pseudonymous-again Mar 31, 2021
56a8aae
:recycle: refactor: Remove usage of class Leaf.
make-github-pseudonymous-again Mar 31, 2021
ccf1b45
:wrench: config(babel): Make current node default.
make-github-pseudonymous-again Mar 31, 2021
7ae67da
:truck: refactor: Rename delete_case1 to delete_case0.
make-github-pseudonymous-again Mar 31, 2021
9652fb1
:truck: refactor: Rename delete_case2 to delete_case1.
make-github-pseudonymous-again Mar 31, 2021
5fd0cf9
:truck: refactor: Rename delete_case3 to delete_case2.
make-github-pseudonymous-again Mar 31, 2021
1bfdbd7
:truck: refactor: Rename delete_case4 to delete_case3.
make-github-pseudonymous-again Mar 31, 2021
3a6cc9d
:truck: refactor: Rename delete_case5 to delete_case4.
make-github-pseudonymous-again Mar 31, 2021
22e1f10
:truck: refactor: Rename delete_case6 to delete_case5.
make-github-pseudonymous-again Mar 31, 2021
c77e38b
:truck: refactor: Rename insert_case1 to insert_case0.
make-github-pseudonymous-again Mar 31, 2021
3161201
:truck: refactor: Rename insert_case2 to insert_case1.
make-github-pseudonymous-again Mar 31, 2021
33a4d31
:truck: refactor: Rename insert_case3 to insert_case2.
make-github-pseudonymous-again Mar 31, 2021
5d6cedc
:truck: refactor: Rename insert_case4 to insert_case3.
make-github-pseudonymous-again Mar 31, 2021
d935d6b
:truck: refactor: Rename insert_case5 to insert_case4.
make-github-pseudonymous-again Mar 31, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions mangle.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
"minify": {
"mangle": {
"properties": {
"regex": "^(_color|isLeaf)$"
"regex": "^_color$"
}
}
},
"props": {
"props": {
"$_color": "c",
"$isLeaf": "L"
"$_color": "c"
}
}
}
76 changes: 39 additions & 37 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"build-gh-pages": "npm run build-docs",
"ci:test": "npm run lint-config && npm run lint && npm run cover",
"commit-msg": "commitlint --edit",
"cover": "c8 --all --src src --reporter=lcov npm test",
"cover": "NODE_ENV=cover c8 --all --src src --reporter=lcov npm test",
"debug": "NODE_ENV=debug npm run test -- -st --fail-fast",
"dev": "npm run lint-config-and-fix && npm run lint-and-fix && npm run cover -- -- -st --fail-fast",
"install-hooks": "husky install",
Expand Down Expand Up @@ -104,40 +104,33 @@
[
"@babel/preset-env",
{
"targets": [
"defaults",
"maintained node versions"
"targets": "current node"
}
]
],
"plugins": [
[
"transform-remove-console",
{
"exclude": [
"log",
"error",
"warn"
]
}
]
],
"env": {
"debug": {
"presets": [
[
"@babel/preset-env",
{
"targets": "current node"
}
],
"babel-preset-power-assert"
]
},
"test": {
"presets": [
[
"@babel/preset-env",
{
"targets": "current node"
}
],
"babel-preset-power-assert"
],
"plugins": [
[
"transform-remove-console",
{
"exclude": [
"debug",
"log",
"error",
"warn"
Expand All @@ -146,36 +139,45 @@
]
]
},
"development": {
"test": {
"presets": [
"babel-preset-power-assert"
],
"plugins": [
]
},
"cover": {
"sourceMaps": "inline",
"presets": [
"babel-preset-power-assert"
]
},
"development": {
"presets": [
[
"transform-remove-console",
"@babel/preset-env",
{
"exclude": [
"log",
"error",
"warn"
"targets": [
"defaults",
"maintained node versions"
]
}
]
],
"babel-preset-power-assert"
]
},
"production": {
"plugins": [
"babel-plugin-unassert",
"presets": [
[
"transform-remove-console",
"@babel/preset-env",
{
"exclude": [
"log",
"error",
"warn"
"targets": [
"defaults",
"maintained node versions"
]
}
]
],
"plugins": [
"babel-plugin-unassert"
]
}
}
Expand Down
9 changes: 2 additions & 7 deletions src/debug/_debug.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import assert from 'assert';
import Node from '../types/Node.js';
import Leaf from '../types/Leaf.js';
import BLACK from '../color/BLACK.js';

/**
Expand All @@ -14,15 +13,11 @@ const _debug = ({red, black}) => {
* Recursively constructs a prettyprint string for the red-black tree rooted at
* <code>root</code>.
*
* @param {Node|Leaf} root - The root of the tree.
* @param {Node} root - The root of the tree.
* @returns {string}
*/
const debug = (root) => {
assert(root instanceof Node || root instanceof Leaf);
if (root.isLeaf()) {
assert(root instanceof Leaf);
return black('L');
}
if (root === null) return black('L');

assert(root instanceof Node);

Expand Down
23 changes: 23 additions & 0 deletions src/deletion/delete_case0.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import assert from 'assert';
import BLACK from '../color/BLACK.js';
import Node from '../types/Node.js';
import delete_case1 from './delete_case1.js';

/**
* Preconditions:
* - n is black
* - all root-leaf paths going through n have a black height of b - 1
* - all other root-leaf paths have a black height of b
*
* @param {Node} n - The input node.
*/
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);
};

export default delete_case0;
42 changes: 35 additions & 7 deletions src/deletion/delete_case1.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,52 @@
import assert from 'assert';
import BLACK from '../color/BLACK.js';
import RED from '../color/RED.js';
import Node from '../types/Node.js';
import Leaf from '../types/Leaf.js';
import rotate_left from '../rotate/rotate_left.js';
import rotate_right from '../rotate/rotate_right.js';
import sibling from '../family/sibling.js';

import delete_case2 from './delete_case2.js';
import delete_case3 from './delete_case3.js';

/**
* Preconditions:
* - n is black
* - all root-leaf paths going through n have a black height of b - 1
* - all other root-leaf paths have a black height of b
* - n is not the root
*
* @param {Node|Leaf} n - The input node.
* @param {Node} n - The input node.
*/
const delete_case1 = (n) => {
assert(n instanceof Node || n instanceof Leaf);
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_case2(n);
assert(n.parent !== null);

const s = sibling(n);
assert(s instanceof Node);

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

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

export default delete_case1;
44 changes: 23 additions & 21 deletions src/deletion/delete_case2.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,52 @@ import assert from 'assert';
import BLACK from '../color/BLACK.js';
import RED from '../color/RED.js';
import Node from '../types/Node.js';
import Leaf from '../types/Leaf.js';
import rotate_left from '../rotate/rotate_left.js';
import rotate_right from '../rotate/rotate_right.js';
import sibling from '../family/sibling.js';

import delete_case0 from './delete_case0.js';
import delete_case3 from './delete_case3.js';
import delete_case4 from './delete_case4.js';

/**
* Preconditions:
* - n is black
* - all root-leaf paths going through n have a black height of b - 1
* - all other root-leaf paths have a black height of b
* - n is not the root
* - n's sibling is black
*
* @param {Node|Leaf} n - The input node.
* @param {Node} n - The input node.
*/
const delete_case2 = (n) => {
assert(n instanceof Node || n instanceof Leaf);
assert(n instanceof Node);
assert(n._color === BLACK);
assert(n.parent !== null);

const s = sibling(n);
assert(s instanceof Node);
assert(s._color === BLACK);

/**
* If n's sibling is red, prepare for and go to case 4.
* If n's parent is black and n's sibling's children are black, then
* repaint n's sibling red. Now all root-leaf paths going through n's
* parent have a black height of b - 1. We recurse thus on n's parent.
*
* B B
* B >B
* / \ / \
* >B R R B
* / \ / \ --> / \ / \
* - - B B >B B = =
* / \ / \ / \ / \
* = = = = - - = =
* >B B B R
* / \ / \ --> / \ / \
* - - B B - - B B
* / \ / \ / \ / \
* - - - - - - - -
*/
if (s._color === RED) {
n.parent._color = RED;
s._color = BLACK;
if (n === n.parent.left) rotate_left(n.parent);
else rotate_right(n.parent);
delete_case4(n);
if (
n.parent._color === BLACK &&
(s.left === null || s.left._color === BLACK) &&
(s.right === null || s.right._color === BLACK)
) {
s._color = RED;
delete_case0(n.parent);
}

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

Expand Down
Loading