From 3d024e55f72793f6fc9da56d3cb4b3dc16becd29 Mon Sep 17 00:00:00 2001 From: caoglish Date: Wed, 5 Feb 2014 16:01:39 +1100 Subject: [PATCH 1/6] 1. add search and delete in binary search tree 2. add unittest for binary search tree --- solutions/javascript/binary-search-tree.js | 114 ++++++++++++++++----- tests/javascript/binary-search-tree.js | 53 ++++++++++ 2 files changed, 141 insertions(+), 26 deletions(-) create mode 100644 tests/javascript/binary-search-tree.js diff --git a/solutions/javascript/binary-search-tree.js b/solutions/javascript/binary-search-tree.js index 6f5e74d..22fbf93 100644 --- a/solutions/javascript/binary-search-tree.js +++ b/solutions/javascript/binary-search-tree.js @@ -1,37 +1,99 @@ var root, - createNode, - add; - -createNode = function createNode(num) { - return { - add: add, - left: undefined, - right: undefined, - value: num +createNode, +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 + }; + }; + + addSubNode = function(num, direct) { + if (this[direct] === undefined) { + this[direct] = createNode(num); + } else { + this[direct].add(num); + } }; + + add = function(num) { + if (this.value === undefined) { + this.value = num; + } else { + if (num < this.value) { + addSubNode.apply(this, [num, 'left']); + } else if (num > this.value) { + addSubNode.apply(this, [num, 'right']); + } //ignore the existed one. + } + + //always return root + 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; + } }; -add = function add(num) { - if (this.value === undefined) { - this.value = num; +findRightMost = function () { + if (this.right === undefined){ return this; } + return findRightMost.call(this.right); +}; + +replaceNodeInParent = function (parent, newNode) { + if(parent.left===this) { + parent.left = newNode; + }else { + parent.right = newNode; + } +}; + + +binaryTreeDelete = function(num,parent) { + var successor; + //if only root in the true; + if(root===this&&this.left === undefined && this.right === undefined){ + root= undefined; + return root; + } + + 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 { - if (num < this.value) { - if (this.left === undefined) { - this.left = createNode(num); - } else { - this.left.add(num); - } - } else if (num > this.value) { - if (this.right === undefined) { - this.right = createNode(num); - } else { - this.right.add(num); - } + //delete key here + if (this.left !== undefined && this.right !== undefined||root===this) { + successor = findRightMost.call(this.left); + this.value= successor.value; + this.left.delete(successor.value,this); + } else if (this.left) { + replaceNodeInParent.apply(this, [parent, this.left]); + } else if (this.right) { + replaceNodeInParent.apply(this, [parent, this.right]); } else { - return false; + replaceNodeInParent.apply(this, [parent]);//replace with undefined } } return root; }; -module.exports = (root = createNode(undefined)); +module.exports = (root = createNode(undefined)); \ No newline at end of file diff --git a/tests/javascript/binary-search-tree.js b/tests/javascript/binary-search-tree.js new file mode 100644 index 0000000..8d4a60b --- /dev/null +++ b/tests/javascript/binary-search-tree.js @@ -0,0 +1,53 @@ +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); + +describe('binary search tree', function() { + it('root should pass a valid binary search tree', function() { + assert.ok(isBST(root)); + assert.equal(JSON.stringify(root), + '{"left":{"left":{"left":{"value":6},"right":{"value":8},"value":7},"right":{"value":10},"value":9},"right":{"left":{"value":75},"right":{"left":{"value":125},"right":{"value":175},"value":150},"value":100},"value":50}'); + }); + + it('deleting nodes should pass a valid binary search tree', function() { + root.delete(125) + .delete(9) + .delete(75) + assert.ok(isBST(root)); + assert.equal(JSON.stringify(root), + '{"left":{"left":{"left":{"value":6},"value":7},"right":{"value":10},"value":8},"right":{"right":{"right":{"value":175},"value":150},"value":100},"value":50}'); + }); + + 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.equal(JSON.stringify(root), + '{"left":{"left":{"left":{"value":6},"value":7},"right":{"value":10},"value":8},"right":{"right":{"right":{"value":175},"value":150},"value":100},"value":50}'); + }); + + it('search nodes', function() { + var node = root.search(999999); // if not existed + assert.ok(!node); + + node = root.search(125); + assert.ok(!node); + + node = root.search(7); // if existed + assert.equal(JSON.stringify(node), '{"left":{"value":6},"value":7}'); + + + node = root.search(100); // if existed + assert.equal(JSON.stringify(node), '{"right":{"right":{"value":175},"value":150},"value":100}'); + + node = root.search(50); // if existed + assert.equal(JSON.stringify(node), + '{"left":{"left":{"left":{"value":6},"value":7},"right":{"value":10},"value":8},"right":{"right":{"right":{"value":175},"value":150},"value":100},"value":50}'); + + }); + + +}); \ No newline at end of file From 0dd889f788028fab6a417c176a50da1a2b5c0d31 Mon Sep 17 00:00:00 2001 From: caoglish Date: Wed, 5 Feb 2014 16:06:41 +1100 Subject: [PATCH 2/6] 1. format the code --- solutions/javascript/binary-search-tree.js | 94 +++++++++++----------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/solutions/javascript/binary-search-tree.js b/solutions/javascript/binary-search-tree.js index 22fbf93..a9540fb 100644 --- a/solutions/javascript/binary-search-tree.js +++ b/solutions/javascript/binary-search-tree.js @@ -1,39 +1,39 @@ var root, -createNode, -add, -search, -addSubNode, -findRightMost, -replaceNodeInParent, + createNode, + 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 - }; +createNode = function createNode(num) { + return { + add: add, + search: search, + delete: binaryTreeDelete, + left: undefined, + right: undefined, + value: num }; +}; - addSubNode = function(num, direct) { - if (this[direct] === undefined) { - this[direct] = createNode(num); - } else { - this[direct].add(num); - } - }; +addSubNode = function(num, direct) { + if (this[direct] === undefined) { + this[direct] = createNode(num); + } else { + this[direct].add(num); + } +}; - add = function(num) { - if (this.value === undefined) { - this.value = num; - } else { - if (num < this.value) { - addSubNode.apply(this, [num, 'left']); - } else if (num > this.value) { - addSubNode.apply(this, [num, 'right']); +add = function(num) { + if (this.value === undefined) { + this.value = num; + } else { + if (num < this.value) { + addSubNode.apply(this, [num, 'left']); + } else if (num > this.value) { + addSubNode.apply(this, [num, 'right']); } //ignore the existed one. } @@ -53,44 +53,46 @@ search = function(num) { } }; -findRightMost = function () { - if (this.right === undefined){ return this; } +findRightMost = function() { + if (this.right === undefined) { + return this; + } return findRightMost.call(this.right); }; -replaceNodeInParent = function (parent, newNode) { - if(parent.left===this) { +replaceNodeInParent = function(parent, newNode) { + if (parent.left === this) { parent.left = newNode; - }else { + } else { parent.right = newNode; } }; -binaryTreeDelete = function(num,parent) { +binaryTreeDelete = function(num, parent) { var successor; //if only root in the true; - if(root===this&&this.left === undefined && this.right === undefined){ - root= undefined; + if (root === this && this.left === undefined && this.right === undefined) { + root = undefined; return root; } - 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; + 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||root===this) { + if (this.left !== undefined && this.right !== undefined || root === this) { successor = findRightMost.call(this.left); - this.value= successor.value; - this.left.delete(successor.value,this); + this.value = successor.value; + this.left.delete(successor.value, this); } else if (this.left) { replaceNodeInParent.apply(this, [parent, this.left]); } else if (this.right) { replaceNodeInParent.apply(this, [parent, this.right]); } else { - replaceNodeInParent.apply(this, [parent]);//replace with undefined + replaceNodeInParent.apply(this, [parent]); //replace with undefined } } return root; From b6aee518110d87389897c870488fc2689b26d348 Mon Sep 17 00:00:00 2001 From: caoglish Date: Thu, 6 Feb 2014 11:44:40 +1100 Subject: [PATCH 3/6] 1. improving delete when BST dealing with root node. 2. modify avoid using call and apply style --- solutions/javascript/binary-search-tree.js | 48 +++++++++++----------- tests/javascript/binary-search-tree.js | 3 ++ 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/solutions/javascript/binary-search-tree.js b/solutions/javascript/binary-search-tree.js index a9540fb..72209aa 100644 --- a/solutions/javascript/binary-search-tree.js +++ b/solutions/javascript/binary-search-tree.js @@ -18,11 +18,11 @@ createNode = function createNode(num) { }; }; -addSubNode = function(num, direct) { - if (this[direct] === undefined) { - this[direct] = createNode(num); +addSubNode = function(node, direct, num) { + if (node[direct] === undefined) { + node[direct] = createNode(num); } else { - this[direct].add(num); + node[direct].add(num); } }; @@ -31,10 +31,10 @@ add = function(num) { this.value = num; } else { if (num < this.value) { - addSubNode.apply(this, [num, 'left']); + addSubNode(this, 'left', num); } else if (num > this.value) { - addSubNode.apply(this, [num, 'right']); - } //ignore the existed one. + addSubNode(this, 'right', num); + } } //always return root @@ -53,15 +53,21 @@ search = function(num) { } }; -findRightMost = function() { - if (this.right === undefined) { - return this; +findRightMost = function(node) { + if (node.right === undefined) { + return node; } - return findRightMost.call(this.right); + return findRightMost(node.right); }; -replaceNodeInParent = function(parent, newNode) { - if (parent.left === this) { +replaceNodeInParent = function(node,parent, newNode) { + //root's parent is undefined. + if (parent === undefined) { + root = newNode; + return; + } + + if (parent.left === node) { parent.left = newNode; } else { parent.right = newNode; @@ -71,11 +77,6 @@ replaceNodeInParent = function(parent, newNode) { binaryTreeDelete = function(num, parent) { var successor; - //if only root in the true; - if (root === this && this.left === undefined && this.right === undefined) { - root = undefined; - return root; - } if (num < this.value) { return this.left ? this.left.delete(num, this) : root; @@ -83,16 +84,17 @@ binaryTreeDelete = function(num, parent) { return this.right ? this.right.delete(num, this) : root; } else { //delete key here - if (this.left !== undefined && this.right !== undefined || root === this) { - successor = findRightMost.call(this.left); + if (this.left !== undefined && this.right !== undefined) { + console.log(this.left); + successor = findRightMost(this.left); this.value = successor.value; this.left.delete(successor.value, this); } else if (this.left) { - replaceNodeInParent.apply(this, [parent, this.left]); + replaceNodeInParent(this, parent, this.left); } else if (this.right) { - replaceNodeInParent.apply(this, [parent, this.right]); + replaceNodeInParent(this, parent, this.right); } else { - replaceNodeInParent.apply(this, [parent]); //replace with undefined + replaceNodeInParent(this, parent); //replace with undefined } } return root; diff --git a/tests/javascript/binary-search-tree.js b/tests/javascript/binary-search-tree.js index 8d4a60b..9db3c19 100644 --- a/tests/javascript/binary-search-tree.js +++ b/tests/javascript/binary-search-tree.js @@ -50,4 +50,7 @@ describe('binary search tree', function() { }); + + + }); \ No newline at end of file From 788792ec8f6227d326955c18a1904197c6a49ead Mon Sep 17 00:00:00 2001 From: caoglish Date: Thu, 6 Feb 2014 11:54:45 +1100 Subject: [PATCH 4/6] 1. fix style. --- solutions/javascript/binary-search-tree.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/solutions/javascript/binary-search-tree.js b/solutions/javascript/binary-search-tree.js index 72209aa..a5aec76 100644 --- a/solutions/javascript/binary-search-tree.js +++ b/solutions/javascript/binary-search-tree.js @@ -27,6 +27,8 @@ addSubNode = function(node, direct, 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 { @@ -37,7 +39,6 @@ add = function(num) { } } - //always return root return root; }; @@ -61,7 +62,7 @@ findRightMost = function(node) { }; replaceNodeInParent = function(node,parent, newNode) { - //root's parent is undefined. + // root's parent is undefined. if (parent === undefined) { root = newNode; return; @@ -83,7 +84,7 @@ binaryTreeDelete = function(num, parent) { } else if (num > this.value) { return this.right ? this.right.delete(num, this) : root; } else { - //delete key here + // delete key here if (this.left !== undefined && this.right !== undefined) { console.log(this.left); successor = findRightMost(this.left); @@ -94,7 +95,7 @@ binaryTreeDelete = function(num, parent) { } else if (this.right) { replaceNodeInParent(this, parent, this.right); } else { - replaceNodeInParent(this, parent); //replace with undefined + replaceNodeInParent(this, parent); // replace with undefined } } return root; From 375746a9a0881ba18cef50b987c9cf357aad35da Mon Sep 17 00:00:00 2001 From: caoglish Date: Thu, 6 Feb 2014 17:25:50 +1100 Subject: [PATCH 5/6] 1.improving delete when BST dealing with root 2.fix style 3.more unit testing for BST --- solutions/javascript/binary-search-tree.js | 13 ++- tests/javascript/binary-search-tree.js | 120 ++++++++++++++++----- 2 files changed, 101 insertions(+), 32 deletions(-) diff --git a/solutions/javascript/binary-search-tree.js b/solutions/javascript/binary-search-tree.js index a5aec76..645b39f 100644 --- a/solutions/javascript/binary-search-tree.js +++ b/solutions/javascript/binary-search-tree.js @@ -38,7 +38,6 @@ add = function(num) { addSubNode(this, 'right', num); } } - return root; }; @@ -61,10 +60,16 @@ findRightMost = function(node) { return findRightMost(node.right); }; -replaceNodeInParent = function(node,parent, newNode) { +replaceNodeInParent = function(node, parent, newNode) { // root's parent is undefined. if (parent === undefined) { - root = newNode; + if (newNode) { + root.value = newNode.value, + root.left = newNode.left, + root.right = newNode.right; + }else{ + root.value=undefined; + } return; } @@ -78,7 +83,6 @@ replaceNodeInParent = function(node,parent, 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) { @@ -86,7 +90,6 @@ binaryTreeDelete = function(num, parent) { } else { // delete key here if (this.left !== undefined && this.right !== undefined) { - console.log(this.left); successor = findRightMost(this.left); this.value = successor.value; this.left.delete(successor.value, this); diff --git a/tests/javascript/binary-search-tree.js b/tests/javascript/binary-search-tree.js index 9db3c19..7bf329d 100644 --- a/tests/javascript/binary-search-tree.js +++ b/tests/javascript/binary-search-tree.js @@ -1,56 +1,122 @@ var assert = require('assert'); var isBST = require('../../solutions/javascript/binary-search-tree-check'); -var bst = require("../../solutions/javascript/binary-search-tree"); +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.equal(JSON.stringify(root), - '{"left":{"left":{"left":{"value":6},"right":{"value":8},"value":7},"right":{"value":10},"value":9},"right":{"left":{"value":75},"right":{"left":{"value":125},"right":{"value":175},"value":150},"value":100},"value":50}'); + assert.deepEqual(jsonify(root), jsonify(expect)); }); it('deleting nodes should pass a valid binary search tree', function() { - root.delete(125) - .delete(9) - .delete(75) - assert.ok(isBST(root)); - assert.equal(JSON.stringify(root), - '{"left":{"left":{"left":{"value":6},"value":7},"right":{"value":10},"value":8},"right":{"right":{"right":{"value":175},"value":150},"value":100},"value":50}'); - }); + root.delete(125).delete(9).delete(75); - it('deleting unexisted nodes should pass a valid binary search tree', function() { - root.delete(1252222).delete(20392) //delete unexisted node + expect = node(50, + node(8, + node(7, node(6)), + node(10) + ), + node(100, + undefined, + node(150, undefined, node(175)) + ) + ); assert.ok(isBST(root)); - assert.equal(JSON.stringify(root), - '{"left":{"left":{"left":{"value":6},"value":7},"right":{"value":10},"value":8},"right":{"right":{"right":{"value":175},"value":150},"value":100},"value":50}'); + assert.deepEqual(jsonify(root), jsonify(expect)); }); - it('search nodes', function() { - var node = root.search(999999); // if not existed - assert.ok(!node); + 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)); + }); - node = root.search(125); - assert.ok(!node); + it('search nodes', function() { + var searchExpect; + var searchResult = root.search(999999); // if not existed + assert.ok(!searchResult); - node = root.search(7); // if existed - assert.equal(JSON.stringify(node), '{"left":{"value":6},"value":7}'); + searchResult = root.search(125); + assert.ok(!searchResult); - node = root.search(100); // if existed - assert.equal(JSON.stringify(node), '{"right":{"right":{"value":175},"value":150},"value":100}'); + searchExpect = node(7, node(6)); + searchResult = root.search(7); // if existed + assert.deepEqual(jsonify(searchResult), jsonify(searchExpect)); - node = root.search(50); // if existed - assert.equal(JSON.stringify(node), - '{"left":{"left":{"left":{"value":6},"value":7},"right":{"value":10},"value":8},"right":{"right":{"right":{"value":175},"value":150},"value":100},"value":50}'); + 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 searchExpect; + + root.delete(50); + searchExpect = node(10, node(8, node(7, node(6))), + node(100, undefined, node(150, undefined, node(175)))); + assert.deepEqual(jsonify(root), jsonify(searchExpect)); + + //remove left sub tree + root.delete(10).delete(8).delete(7).delete(6); + searchExpect = node(100, undefined, node(150, undefined, node(175))); + assert.deepEqual(jsonify(root), jsonify(searchExpect)); + + //remove right sub tree + root.delete(175).delete(150).add(6).add(5).add(8).add(7).delete(100); + searchExpect = node(6, node(5), node(8, node(7))); + assert.deepEqual(jsonify(root), jsonify(searchExpect)); + + //remove every node. + root.delete(6).delete(5).delete(8).delete(7); + + assert.equal(undefined, root.value); + + + + }); - }); \ No newline at end of file From c1cef17e343770f7af28610ff4529b98c131f67b Mon Sep 17 00:00:00 2001 From: caoglish Date: Thu, 6 Feb 2014 17:35:50 +1100 Subject: [PATCH 6/6] change proper variable name and clean the4 space in unit test --- tests/javascript/binary-search-tree.js | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/tests/javascript/binary-search-tree.js b/tests/javascript/binary-search-tree.js index 7bf329d..2599baf 100644 --- a/tests/javascript/binary-search-tree.js +++ b/tests/javascript/binary-search-tree.js @@ -25,7 +25,6 @@ var jsonify = function(object) { var expect; - describe('binary search tree', function() { it('root should pass a valid binary search tree', function() { expect = node(50, @@ -75,7 +74,6 @@ describe('binary search tree', function() { searchResult = root.search(125); assert.ok(!searchResult); - searchExpect = node(7, node(6)); searchResult = root.search(7); // if existed assert.deepEqual(jsonify(searchResult), jsonify(searchExpect)); @@ -91,32 +89,25 @@ describe('binary search tree', function() { }); it('delete root', function() { - var searchExpect; + var rootExpect; root.delete(50); - searchExpect = node(10, node(8, node(7, node(6))), + rootExpect = node(10, node(8, node(7, node(6))), node(100, undefined, node(150, undefined, node(175)))); - assert.deepEqual(jsonify(root), jsonify(searchExpect)); + assert.deepEqual(jsonify(root), jsonify(rootExpect)); //remove left sub tree root.delete(10).delete(8).delete(7).delete(6); - searchExpect = node(100, undefined, node(150, undefined, node(175))); - assert.deepEqual(jsonify(root), jsonify(searchExpect)); + 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); - searchExpect = node(6, node(5), node(8, node(7))); - assert.deepEqual(jsonify(root), jsonify(searchExpect)); + 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); - - - }); - - - }); \ No newline at end of file