@drozdik.m/avl-tree
Version:
Classic implementation of AVL tree with improvements like efficient search of nth item and iterator.
415 lines (414 loc) • 14.5 kB
JavaScript
exports.__esModule = true;
var AVLTreeNode_1 = require("./AVLTreeNode");
var comparator_handler_1 = require("@drozdik.m/comparator-handler");
var AVLTreeIterator_1 = require("./AVLTreeIterator");
var AVLTree = /** @class */ (function () {
//--------------------------------------------------
//---------CONSTRUCTOR------------------------------
//--------------------------------------------------
/**
* Creates new instance of the object.
* @param items Initial items in the binary search tree.
* @param comparator Comparator - It automatically detects IComparable classes.
*/
function AVLTree(items, comparator) {
if (items === void 0) { items = []; }
if (comparator === void 0) { comparator = null; }
//--------------------------------------------------
//----------VARIABLES-------------------------------
//--------------------------------------------------
this.comparator = null;
this.root = null;
this.comparator = new comparator_handler_1.ComparatorHandler(comparator);
this.Build(items);
}
//--------------------------------------------------
//---------VALUE------------------------------------
//--------------------------------------------------
AVLTree.prototype.Insert = function (item) {
this.root = this.InsertRec(item, this.root);
this.root.parent = null;
};
/**
* Recursive insert method
* @param value Value to insert
* @param node Current node
*/
AVLTree.prototype.InsertRec = function (value, node) {
//Bottom reached, return new node
if (node == null)
return new AVLTreeNode_1.AVLTreeNode(value);
//Go to left subtree
if (this.comparator.Compare(value, node.value) == -1)
node.left = this.InsertRec(value, node.left);
//Go to right subtree
else if (this.comparator.Compare(value, node.value) == 1)
node.right = this.InsertRec(value, node.right);
node.Update();
//This value already exists
return this.RotateAdvisorInsert(node);
};
AVLTree.prototype.Find = function (item) {
return new AVLTreeIterator_1.AVLTreeIterator(this.FindNode(item));
};
/**
* Return node by inserted value
* @param item
*/
AVLTree.prototype.FindNode = function (item) {
return this.FindRec(item, this.root);
};
/**
* Recursive function for searching
* @param value Value
* @param node Current/Initial node
*/
AVLTree.prototype.FindRec = function (value, node) {
//Bottom reached, not found, return null
if (node == null)
return null;
//Go left
if (this.comparator.Compare(node.value, value) == 1)
return this.FindRec(value, node.left);
//Go right
else if (this.comparator.Compare(node.value, value) == -1)
return this.FindRec(value, node.right);
//Found the node
return node;
};
AVLTree.prototype.RemoveAt = function (iterator) {
if (!iterator.HasValue())
return;
this.root = this.DeleteRec(iterator.Value(), this.root);
if (this.root != null)
this.root.parent == null;
};
AVLTree.prototype.Remove = function (item) {
this.RemoveAt(this.Find(item));
};
/**
* Recursive function sor deleting
* @param value Value to delete
* @param node Current node/Initial node
*/
AVLTree.prototype.DeleteRec = function (value, node) {
//At the bottom
if (node == null)
return null;
//Go left
if (this.comparator.Compare(value, node.value) == -1)
node.left = this.DeleteRec(value, node.left);
//Go right
else if (this.comparator.Compare(value, node.value) == 1)
node.right = this.DeleteRec(value, node.right);
//Found the node
else {
//No children
if (node.left == null && node.right == null)
return null;
//Child on right side
else if (node.left == null)
return node.right;
//Child on left side
else if (node.right == null)
return node.left;
//Two children
var successor = this.FindMinRec(node.right);
node.value = successor.value;
node.right = this.DeleteRec(successor.value, node.right);
}
//Climbing up
node.Update();
return this.RotateAdvisorDelete(node);
};
AVLTree.prototype.UpdateAt = function (newValue, iterator) {
//No value
if (!iterator.HasValue())
return;
//New value already exists
if (this.Find(newValue).HasValue())
return;
//Delete current node
this.RemoveAt(iterator);
//Insert node with new value
this.Insert(newValue);
};
AVLTree.prototype.Update = function (oldValue, newValue) {
this.UpdateAt(newValue, this.Find(oldValue));
};
//--------------------------------------------------
//---------AT---------------------------------------
//--------------------------------------------------
AVLTree.prototype.At = function (index) {
return this.AtIterator(index).Value();
};
AVLTree.prototype.AtIterator = function (index) {
//Index out of bounds
if (index > this.Count() - 1 || index < 0)
return new AVLTreeIterator_1.AVLTreeIterator(null);
return new AVLTreeIterator_1.AVLTreeIterator(this.AtRec(index, this.root));
};
/**
* Recursive function for finding nth index
* @param index Index
* @param node Initial/Current node
*/
AVLTree.prototype.AtRec = function (index, node) {
//Reached the end (should not occur)
if (node == null)
return null;
//Found the node
if (node.CountLeft() == index)
return node;
//Go left
if (node.CountLeft() > index)
return this.AtRec(index, node.left);
//Go right
else
return this.AtRec(index - node.CountLeft() - 1, node.right);
};
//--------------------------------------------------
//---------MIN-MAX----------------------------------
//--------------------------------------------------
AVLTree.prototype.FindMin = function () {
return new AVLTreeIterator_1.AVLTreeIterator(this.FindMinRec(this.root));
};
AVLTree.prototype.FindMinRec = function (node) {
//Node is null
if (node == null)
return null;
//We are at the most left
if (node.left == null)
return node;
//Go deeper 0===3 (lil joke heh)
return this.FindMinRec(node.left);
};
AVLTree.prototype.FindMax = function () {
return new AVLTreeIterator_1.AVLTreeIterator(this.FindMaxRec(this.root));
};
AVLTree.prototype.FindMaxRec = function (node) {
//Node is null
if (node == null)
return null;
//We are at the most right
if (node.right == null)
return node;
//Go deeper
return this.FindMaxRec(node.right);
};
//--------------------------------------------------
//---------CLEARS-----------------------------------
//--------------------------------------------------
AVLTree.prototype.Dispose = function () {
this.Clear();
this.comparator.Dispose();
};
AVLTree.prototype.Clear = function () {
this.root = null;
};
//--------------------------------------------------
//---------ITERATOR---------------------------------
//--------------------------------------------------
AVLTree.prototype.First = function () {
return this.FindMin();
};
AVLTree.prototype.Last = function () {
return this.FindMax();
};
//--------------------------------------------------
//---------CLONE------------------------------------
//--------------------------------------------------
AVLTree.prototype.Clone = function () {
var res = new AVLTree();
res.comparator = this.comparator.Clone();
res.root = this.CloneRec(this.root);
return res;
};
/**
* Recursive clone function that clones nodes
* @param node Root/Current node
* @param parent Nodes parent node
*/
AVLTree.prototype.CloneRec = function (node, parent) {
if (parent === void 0) { parent = null; }
if (node == null)
return null;
var res = node.Clone();
res.left = this.CloneRec(res.left, res);
res.right = this.CloneRec(res.right, res);
res.parent = parent;
return res;
};
//--------------------------------------------------
//---------OTHERS-----------------------------------
//--------------------------------------------------
AVLTree.prototype.Build = function (items) {
for (var i = 0; i < items.length; i++)
this.Insert(items[i]);
};
AVLTree.prototype.Count = function () {
if (this.root == null)
return 0;
return this.root.Count();
};
AVLTree.prototype.IsEmpty = function () {
return this.Count() == 0;
};
//--------------------------------------------------
//---------ROTATIONS--------------------------------
//--------------------------------------------------
/**
* Rotate a node in left direction
* @param x Node to rotate around
* @returns Higher node in tree hierarchy
*/
AVLTree.prototype.RotateLeft = function (x) {
//Check if parent exists
if (x == null || x.right == null)
return null;
//Get all variables
var y = x.right;
var b = y.left;
//Switcharino
y.left = x;
x.right = b;
//Parents
if (x.parent != null) {
y.parent = x.parent;
//Update parents reference
if (y.parent.left == x)
y.parent.left = y;
else if (y.parent.right == x)
y.parent.right = y;
}
else
x.parent = null;
//X was root
if (x == this.root) {
this.root = y;
y.parent = null;
}
//Update nodes
x.Update();
y.Update();
return y;
};
/**
* Rotate a node in right direction
* @param y Node to rotate around
* @returns Higher node in tree hierarchy
*/
AVLTree.prototype.RotateRight = function (y) {
//Check if parent exists
if (y == null || y.left == null)
return null;
//Get all variables
var x = y.left;
var b = x.right;
//Switcharino
y.left = b;
x.right = y;
//Parents
if (y.parent != null) {
x.parent = y.parent;
//Update parents pointer
if (x.parent.left == y)
x.parent.left = x;
else if (x.parent.right == y)
x.parent.right = x;
}
else
x.parent = null;
//Y was root
if (y == this.root) {
this.root = x;
x.parent = null;
}
//Update nodes
y.Update();
x.Update();
return x;
};
/**
* Rotate a node to left and right
* @param x Node to rotate around
* @returns Higher node in tree hierarchy
*/
AVLTree.prototype.RotateLeftRight = function (x) {
var y = x.left;
var z = this.RotateLeft(y);
this.RotateRight(x);
return z;
};
/**
* Rotate a node to right and left
* @param x Node to rotate around
* @returns Higher node in tree hierarchy
*/
AVLTree.prototype.RotateRightLeft = function (x) {
var y = x.right;
var z = this.RotateRight(y);
this.RotateLeft(x);
return z;
};
/**
* Rotates the node if needed.
* @param node Node to check
* @returns Higher node in tree hierarchy
*/
AVLTree.prototype.RotateAdvisorInsert = function (node) {
//Rotate right needed
if (node.sign == -2) {
if (node.left != null) {
if (node.left.sign == -1)
return this.RotateRight(node);
else if (node.left.sign == 1)
return this.RotateLeftRight(node);
}
}
//Rotate left needed
else if (node.sign == 2) {
if (node.right != null) {
if (node.right.sign == 1)
return this.RotateLeft(node);
else if (node.right.sign == -1)
return this.RotateRightLeft(node);
}
}
//No rotation needed
return node;
};
/**
* Rotates the node if needed.
* @param node Node to check
* @returns Higher node in tree hierarchy
*/
AVLTree.prototype.RotateAdvisorDelete = function (node) {
//Rotate left needed
if (node.sign == 2) {
if (node.right != null) {
if (node.right.sign == 1)
return this.RotateLeft(node);
else if (node.right.sign == 0)
return this.RotateLeft(node);
else if (node.right.sign == -1)
return this.RotateRightLeft(node);
}
}
//Rotate right needed
else if (node.sign == -2) {
if (node.left != null) {
if (node.left.sign == -1)
return this.RotateRight(node);
else if (node.left.sign == 0)
return this.RotateRight(node);
else if (node.left.sign == 1)
return this.RotateLeftRight(node);
}
}
//No rotation needed
return node;
};
return AVLTree;
}());
exports.AVLTree = AVLTree;