Skip to content

Commit

Permalink
Now the updateChild could be able override by external code.
Browse files Browse the repository at this point in the history
and along with insertLeafNode & removeLeafNode
  • Loading branch information
lygstate committed Jan 6, 2016
1 parent efeda27 commit bddeca7
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 137 deletions.
241 changes: 111 additions & 130 deletions src/data-structures/size-balanced-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,7 @@
* @module data-structures/size-balanced-tree
*/

function CreateSBTreeClass (Node, Nil) {
function updateChild(node, newChild) {
var parent = node.parent;
if (parent !== Nil) {
if (parent.right === node) {
parent.right = newChild;
} else {
parent.left = newChild;
}
parent.updateSize();
}
if (newChild !== Nil) {
newChild.parent = parent;
}
}

function CreateSBTreeClass (Node, Nil, updateChild) {
function LeftRotate(node, childNode) {
/*
Before rotate:
Expand All @@ -69,9 +54,8 @@ function CreateSBTreeClass (Node, Nil) {
node.right.parent = node;
}
childNode.left = node;
updateChild(node, childNode); //Access node.parent
node.parent = childNode;
node.updateSize();
// setting childNode's parent to node's parent
updateChild(node, childNode);
return childNode;
}

Expand All @@ -96,9 +80,8 @@ function CreateSBTreeClass (Node, Nil) {
node.left.parent = node;
}
childNode.right = node;
updateChild(node, childNode); //Access node.parent
node.parent = childNode;
node.updateSize();
// setting childNode's parent to node's parent
updateChild(node, childNode);
return childNode;
}

Expand All @@ -122,7 +105,6 @@ function CreateSBTreeClass (Node, Nil) {
node = LeftRotate(node, node.right);
}
}
node.updateSize();
if (node === savedNode) {
return node;
}
Expand All @@ -146,20 +128,6 @@ function CreateSBTreeClass (Node, Nil) {
return node;
}

function findRightMost(node) {
while (node.right !== Nil) {
node = node.right;
}
return node;
}

function findLeftMost(node) {
while (node.left !== Nil) {
node = node.left;
}
return node;
}

function findNodeAtPos(node, pos) {
while (pos !== node.left.size) {
if (pos < node.left.size) {
Expand All @@ -183,7 +151,6 @@ function CreateSBTreeClass (Node, Nil) {

SBTree.prototype = {
_root: Nil,
updateChild: updateChild,
get size() {
return this._root.size;
},
Expand All @@ -208,26 +175,8 @@ function CreateSBTreeClass (Node, Nil) {
},
};

/**
* Push a value to the end of tree.
* Complexity: O(log N).
*
* @public
* @method
* @param {Object} value Value.
*/
SBTree.prototype.push = function (value) {
var node = findRightMost(this._root);
var newNode = new Node(value, node, Nil, Nil, 1);
if (node !== Nil) {
node.right = newNode;
}
this._root = maintainSizeBalancedTree(newNode);
return newNode;
};

SBTree.prototype.get = function (pos) {
if (pos >= this._root.size) {
if (pos >= this.size) {
return Nil;
}
return findNodeAtPos(this._root, pos);
Expand All @@ -245,83 +194,97 @@ function CreateSBTreeClass (Node, Nil) {
return index;
};

SBTree.prototype.insert = function (pos, value) {
if (pos >= this._root.size) {
return this.push(value);
SBTree.prototype.shiftDown = function (node) {
var direction = 0;
while (true) {
if (node.left !== Nil && node.right !== Nil) {
switch (direction) {
case 0:
RightRotate(node, node.left);
break;
case 1:
LeftRotate(node, node.right);
break;
}
direction = 1 - direction;
} else if (node.left !== Nil) {
RightRotate(node, node.left);
} else if (node.right !== Nil) {
LeftRotate(node, node.right);
} else {
break; // The node could be able to removed
}
}
var node = findNodeAtPos(this._root, pos);
var newNode;
if (node.left === Nil) {
newNode = new Node(value, node, Nil, Nil, 1);
node.left = newNode;
};

SBTree.prototype.insertLeafNode = function (node) {
var parent = node.parent;
while (parent !== Nil) {
parent.size = parent.size + 1;
parent = parent.parent;
}
};

SBTree.prototype.removeLeafNode = function (node) {
var parent = node.parent;
while (parent !== Nil) {
parent.size = parent.size - 1;
parent = parent.parent;
}
};

SBTree.prototype.insert = function (pos, value) {
var node = Nil;
var newNode = new Node(value, Nil, Nil, Nil, 1);
if (pos === this.size) {
if (pos > 0) {
node = findNodeAtPos(this._root, pos - 1);
node.right = newNode;
}
} else {
node = findRightMost(node.left);
newNode = new Node(value, node, Nil, Nil, 1);
node.right = newNode;
node = findNodeAtPos(this._root, pos);
if (node.left !== Nil) {
this.shiftDown(node);
}
node.left = newNode;
}
newNode.parent = node;
this.insertLeafNode(newNode);
this._root = maintainSizeBalancedTree(newNode);
return newNode;
};

/**
* Push a value to the end of tree.
* Complexity: O(log N).
*
* @public
* @method
* @param {Object} value Value.
*/
SBTree.prototype.push = function (value) {
this.insert(this.size, value);
};

SBTree.prototype.removeNode = function (node) {
this.shiftDown(node);
var maintainNode = node.parent;
if (maintainNode.left === node) {
maintainNode.left = Nil;
} else if (maintainNode.right === node) {
maintainNode.right = Nil;
}
this.removeLeafNode(node);
this._root = maintainSizeBalancedTree(maintainNode);
return node;
};

SBTree.prototype.remove = function (pos) {
if (pos >= this._root.size) {
return Nil; // There is no element to remove
}
var node = findNodeAtPos(this._root, pos);
var maintainNode;

/*
Before remove:
P (node's parent, be notices,
| N either be left child or right child of P)
|
N(node)
/ \
L R
\
\
LRM(Left-Rightmost)
\
Nil
After remove node N:
P(node's parent)
/
L
\
\
LRM(Left-Rightmost)
\
R
N(node) is wild node that was removed
*/
if (node.left !== Nil){
var LRM = findRightMost(node.left);
updateChild(node, node.left);
LRM.right = node.right;
if (LRM.right === Nil) {
maintainNode = LRM;
} else {
LRM.right.parent = LRM;
maintainNode = LRM.right;
}
} else if (node.right !== Nil) {
var RLM = findLeftMost(node.right);
updateChild(node, node.right);
RLM.left = node.left;
if (RLM.left === Nil) {
maintainNode = RLM;
} else {
RLM.left.parent = RLM;
maintainNode = RLM.left;
}
} else {
updateChild(node, Nil);
maintainNode = node.parent;
}
this._root = maintainSizeBalancedTree(maintainNode);
return node;
return this.removeNode(node);
};

return SBTree;
Expand Down Expand Up @@ -349,6 +312,14 @@ function CreateSBTreeClass (Node, Nil) {
this.height = 0;
};

var createNil = function (Node, value) {
var Nil = new Node(value, null, null, null, 0);
Nil.parent = Nil;
Nil.left = Nil;
Nil.right = Nil;
return Nil;
};

/**
* Update node's size.
*
Expand All @@ -360,12 +331,22 @@ function CreateSBTreeClass (Node, Nil) {
this.height = Math.max(this.left.height, this.right.height) + 1;
};

var createNil = function (Node, value) {
var Nil = new Node(value, null, null, null, 0);
Nil.parent = Nil;
Nil.left = Nil;
Nil.right = Nil;
return Nil;
// node, childNode must not be Nil,
// if the childNode turn out to be the root, the parent should be Nil
var updateChild = function (node, childNode) {
var parent = node.parent;
node.parent = childNode;
childNode.parent = parent;

node.updateSize();
childNode.updateSize();
if (parent.right === node) {
parent.right = childNode;
parent.updateSize();
} else if (parent.left === node) {
parent.left = childNode;
parent.updateSize();
} // otherwise parent is Nil
};

var Node = function () {
Expand All @@ -379,11 +360,11 @@ function CreateSBTreeClass (Node, Nil) {
exports.NodeConstructor = NodeConstructor;
exports.createNil = createNil;
exports.updateSize = updateSize;
exports.updateChild = updateChild;
exports.CreateSBTreeClass = CreateSBTreeClass;

exports.Node = Node;
exports.Nil = Nil;
exports.SBTree = CreateSBTreeClass(Node, Nil);
exports.updateChild = exports.SBTree.prototype.updateChild;
exports.SBTree = CreateSBTreeClass(Node, Nil, updateChild);

})(typeof module === 'undefined' ? window : module.exports);
8 changes: 1 addition & 7 deletions test/data-structures/size-balanced-tree.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ describe('SBTree', function () {
}

it('test updateChild', function () {
updateChild(Nil, Nil);
checkNil();
var root = new Node(10, Nil, Nil, Nil, 1);
var left = new Node(5, root, Nil, Nil, 1);
Expand All @@ -80,12 +79,7 @@ describe('SBTree', function () {
updateChild(left, leftLeft);
expect(leftLeft.parent).toBe(root);
expect(root.left).toBe(leftLeft);
updateChild(leftLeft, Nil);
checkNil();
expect(root.left).toBe(Nil);
expect(root.size).toBe(2);
updateChild(Nil, right);
expect(right.parent).toBe(Nil);
expect(root.left.size).toBe(1);
checkNil();
});
// Returns a random integer between min (included) and max (excluded)
Expand Down

0 comments on commit bddeca7

Please sign in to comment.