Skip to content
This repository was archived by the owner on Dec 12, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
98 changes: 84 additions & 14 deletions solutions/javascript/binary-search-tree.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,107 @@
var root,
createNode,
add;
add,
search,
addSubNode,
findRightMost,
replaceNodeInParent,
binaryTreeDelete; // not overwrite keyword.

createNode = function createNode(num) {
return {
add: add,
search: search,
delete: binaryTreeDelete,
left: undefined,
right: undefined,
value: num
};
};

add = function add(num) {
addSubNode = function(node, direct, num) {
if (node[direct] === undefined) {
node[direct] = createNode(num);
} else {
node[direct].add(num);
}
};

add = function(num) {
// Add the value to the correct side of the binary search tree.
// If the value is the same as the current node, we'll just ignore it.
if (this.value === undefined) {
this.value = num;
} else {
if (num < this.value) {
if (this.left === undefined) {
this.left = createNode(num);
} else {
this.left.add(num);
}
addSubNode(this, 'left', num);
} else if (num > this.value) {
if (this.right === undefined) {
this.right = createNode(num);
} else {
this.right.add(num);
}
addSubNode(this, 'right', num);
}
}
return root;
};

search = function(num) {
if (num === this.value) {
return this;
} else if (num < this.value && this.left) {
return this.left.search(num);
} else if (num > this.value && this.right) {
return this.right.search(num);
} else {
return false;
}
};

findRightMost = function(node) {
if (node.right === undefined) {
return node;
}
return findRightMost(node.right);
};

replaceNodeInParent = function(node, parent, newNode) {
// root's parent is undefined.
if (parent === undefined) {
if (newNode) {
root.value = newNode.value,
root.left = newNode.left,
root.right = newNode.right;
}else{
root.value=undefined;
}
return;
}

if (parent.left === node) {
parent.left = newNode;
} else {
parent.right = newNode;
}
};


binaryTreeDelete = function(num, parent) {
var successor;
if (num < this.value) {
return this.left ? this.left.delete(num, this) : root;
} else if (num > this.value) {
return this.right ? this.right.delete(num, this) : root;
} else {
// delete key here
if (this.left !== undefined && this.right !== undefined) {
successor = findRightMost(this.left);
this.value = successor.value;
this.left.delete(successor.value, this);
} else if (this.left) {
replaceNodeInParent(this, parent, this.left);
} else if (this.right) {
replaceNodeInParent(this, parent, this.right);
} else {
return false;
replaceNodeInParent(this, parent); // replace with undefined
}
}
return root;
};

module.exports = (root = createNode(undefined));
module.exports = (root = createNode(undefined));
113 changes: 113 additions & 0 deletions tests/javascript/binary-search-tree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
var assert = require('assert');
var isBST = require('../../solutions/javascript/binary-search-tree-check');
var bst = require('../../solutions/javascript/binary-search-tree');

var root = bst.add(50).add(9).add(100)
.add(7).add(10).add(8).add(6)
.add(75).add(150).add(175).add(125);

var node = function(value, left, right) {
var result = {
value: value
};
if (left) {
result.left = left;
}
if (right) {
result.right = right;
}
return result;
};

var jsonify = function(object) {
return JSON.parse(JSON.stringify(object));
};

var expect;

describe('binary search tree', function() {
it('root should pass a valid binary search tree', function() {
expect = node(50,
node(9,
node(7, node(6), node(8)),
node(10)
),
node(100,
node(75),
node(150, node(125), node(175))
)
);

assert.ok(isBST(root));
assert.deepEqual(jsonify(root), jsonify(expect));
});

it('deleting nodes should pass a valid binary search tree', function() {
root.delete(125).delete(9).delete(75);

expect = node(50,
node(8,
node(7, node(6)),
node(10)
),
node(100,
undefined,
node(150, undefined, node(175))
)
);
assert.ok(isBST(root));
assert.deepEqual(jsonify(root), jsonify(expect));
});

it('deleting unexisted nodes should pass a valid binary search tree',
function() {
root.delete(1252222).delete(20392); //delete unexisted node
assert.ok(isBST(root));
assert.deepEqual(jsonify(root), jsonify(expect));
});

it('search nodes', function() {
var searchExpect;
var searchResult = root.search(999999); // if not existed
assert.ok(!searchResult);

searchResult = root.search(125);
assert.ok(!searchResult);

searchExpect = node(7, node(6));
searchResult = root.search(7); // if existed
assert.deepEqual(jsonify(searchResult), jsonify(searchExpect));

searchExpect = node(100, undefined, node(150, undefined, node(175)));
searchResult = root.search(100); // if existed
assert.deepEqual(jsonify(searchResult), jsonify(searchExpect));

searchExpect = node(50, node(8, node(7, node(6)), node(10)),
node(100, undefined, node(150, undefined, node(175))));
searchResult = root.search(50); // if existed
assert.deepEqual(jsonify(searchResult), jsonify(searchExpect));
});

it('delete root', function() {
var rootExpect;

root.delete(50);
rootExpect = node(10, node(8, node(7, node(6))),
node(100, undefined, node(150, undefined, node(175))));
assert.deepEqual(jsonify(root), jsonify(rootExpect));

//remove left sub tree
root.delete(10).delete(8).delete(7).delete(6);
rootExpect = node(100, undefined, node(150, undefined, node(175)));
assert.deepEqual(jsonify(root), jsonify(rootExpect));

//remove right sub tree
root.delete(175).delete(150).add(6).add(5).add(8).add(7).delete(100);
rootExpect = node(6, node(5), node(8, node(7)));
assert.deepEqual(jsonify(root), jsonify(rootExpect));

//remove every node.
root.delete(6).delete(5).delete(8).delete(7);
assert.equal(undefined, root.value);
});
});