avl-sorted-list
Version:
Sorted List Implementation Using AVL Tree Data Structure
222 lines (179 loc) • 3.97 kB
JavaScript
/*
* AVL Tree Implementation
* Teguh Suryo Santoso
* 19-08-2017
*/
'use strict';
function createNewNode_(key) {
return {
key: key,
weight: 1,
height: 0,
left: null,
right: null
};
}
var comparer_ = function(a, b) {
if(a < b) return -1;
if(a > b) return 1;
return 0;
}
function height_(p) {
return p ? p.height : 0;
}
function weight_(p) {
return p ? p.weight : 0;
}
function bFactor_(p) {
return height_(p.right) - height_(p.left);
}
function countHeightAndWeight_(p) {
var hl = height_(p.left);
var hr = height_(p.right);
p.height = (hl > hr ? hl : hr) + 1;
var wl = weight_(p.left);
var wr = weight_(p.right);
p.weight = wl + wr + 1;
}
function rotateRight_(p) {
var q = p.left;
p.left = q.right;
q.right = p;
countHeightAndWeight_(p);
countHeightAndWeight_(q);
return q;
}
function rotateLeft_(q) {
var p = q.right;
q.right = p.left;
p.left = q;
countHeightAndWeight_(q);
countHeightAndWeight_(p);
return p;
}
function balance_(p) {
countHeightAndWeight_(p);
if(bFactor_(p) === 2) {
if(bFactor_(p.right) < 0)
p.right = rotateRight_(p.right);
return rotateLeft_(p);
}
if(bFactor_(p) === -2) {
if(bFactor_(p.left) > 0 )
p.left = rotateLeft_(p.left);
return rotateRight_(p);
}
return p;
}
function lowerBound_(p, k) {
if(!p) return 0;
var cmp = comparer_(k, p.key);
if(cmp <= 0) return lowerBound_(p.left, k);
else if (cmp > 0) return weight_(p.left) + lowerBound_(p.right, k) + 1;
}
function upperBound_(p, k) {
if(!p) return 0;
var cmp = comparer_(k, p.key);
if(cmp < 0) return upperBound_(p.left, k);
else if (cmp >= 0) return weight_(p.left) + upperBound_(p.right, k) + 1;
}
function count_(p, k) {
return upperBound_(p, k) - lowerBound_(p, k);
}
function at_(p, k) {
if(!p) return null;
var wl = weight_(p.left);
if(wl <= k && k < wl + 1) return p.key;
else if(k < wl) return at_(p.left, k);
else return at_(p.right, k - wl - 1);
}
function insert_(p, k) {
if(!p) return createNewNode_(k);
var cmp = comparer_(k, p.key);
if(cmp < 0) p.left = insert_(p.left, k);
else if(cmp >= 0) p.right = insert_(p.right, k);
return balance_(p);
}
function getMinimum_(p) {
if(!p) return null;
return p.left ? getMinimum_(p.left) : p;
}
function getMaximum_(p) {
if(!p) return null;
return p.right ? getMaximum_(p.right) : p;
}
function removeMinimun_(p) {
if(!p.left) return p.right;
p.left = removeMinimun_(p.left);
return balance_(p);
}
function remove_(p, k) {
if(!p) return null;
var cmp = comparer_(k, p.key);
if(cmp < 0) p.left = remove_(p.left, k);
else if(cmp > 0) p.right = remove_(p.right, k);
else {
var q = p.left;
var r = p.right;
//delete p;
if(!r) return q;
var min = getMinimum_(r);
min.right = removeMinimun_(r);
min.left = q;
return balance_(min);
}
return balance_(p);
}
function toArray_(p) {
var arr = [];
if(p.left) arr = arr.concat(toArray_(p.left));
arr.push(p.key);
if(p.right) arr = arr.concat(toArray_(p.right));
return arr;
}
var AVLTree = function(comparer) {
if(comparer) comparer_ = comparer;
var AVL = {
root: null,
size: function() {
return weight_(AVL.root);
},
min: function() {
var p = getMinimum_(AVL.root);
if(p) return p.key;
return null;
},
max: function() {
var p = getMaximum_(AVL.root);
if(p) return p.key;
return null;
},
lowerBound: function(k) {
return lowerBound_(AVL.root, k);
},
upperBound: function(k) {
return upperBound_(AVL.root, k);
},
count: function(k) {
return count_(AVL.root, k);
},
at: function (k) {
return at_(AVL.root, k);
},
insert: function(k) {
AVL.root = insert_(AVL.root, k);
},
remove: function(k) {
AVL.root = remove_(AVL.root, k);
},
removeAt: function(k) {
var val = AVL.at(k);
AVL.root = remove_(AVL.root, val);
},
toArray: function() {
return toArray_(AVL.root);
}
}
return AVL;
}
module.exports = AVLTree;