UNPKG

@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
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;