@drozdik.m/avl-tree
Version:
Classic implementation of AVL tree with improvements like efficient search of nth item and iterator.
546 lines (469 loc) • 15.9 kB
text/typescript
import { IIterableBidirectionaly } from "@drozdik.m/common-interfaces/IIterableBidirectionaly";
import { IClonable } from "@drozdik.m/common-interfaces/IClonable";
import { IContainer } from "@drozdik.m/common-interfaces/IContainer";
import { ICountable } from "@drozdik.m/common-interfaces/ICountable";
import { IClearable } from "@drozdik.m/common-interfaces/IClearable";
import { IDisposable } from "@drozdik.m/common-interfaces/IDisposable";
import { IBidirectionalySearchableContainer } from "@drozdik.m/common-interfaces/IBidirectionalySearchableContainer";
import { IRemovableContainerByIterator } from "@drozdik.m/common-interfaces/IRemovableContainerByIterator";
import { IUpdatableContainerByIterator } from "@drozdik.m/common-interfaces/IUpdatableContainerByIterator";
import { IRandomAccessibleIterable } from "@drozdik.m/common-interfaces/IRandomAccessibleIterable";
import { IComparator } from "@drozdik.m/common-interfaces/IComparator";
import { IBuildable } from "@drozdik.m/common-interfaces/IBuildable";
import { AVLTreeNode } from "./AVLTreeNode";
import { ComparatorHandler } from "@drozdik.m/comparator-handler";
import { AVLTreeIterator } from "./AVLTreeIterator";
export class AVLTree<T> implements IIterableBidirectionaly<T>, IClonable<AVLTree<T>>, IContainer<T>,
ICountable, IClearable, IDisposable, IBidirectionalySearchableContainer<T>, IRemovableContainerByIterator<T>,
IUpdatableContainerByIterator<T>, IRandomAccessibleIterable<T>, IBuildable<T>
{
//--------------------------------------------------
//----------VARIABLES-------------------------------
//--------------------------------------------------
private comparator: ComparatorHandler<T> = null;
private root: AVLTreeNode<T> = null;
//--------------------------------------------------
//---------CONSTRUCTOR------------------------------
//--------------------------------------------------
/**
* Creates new instance of the object.
* @param items Initial items in the binary search tree.
* @param comparator Comparator - It automatically detects IComparable classes.
*/
constructor(items: T[] = [], comparator: IComparator<T> = null)
{
this.comparator = new ComparatorHandler<T>(comparator);
this.Build(items);
}
//--------------------------------------------------
//---------VALUE------------------------------------
//--------------------------------------------------
Insert(item: T): void
{
this.root = this.InsertRec(item, this.root);
this.root.parent = null;
}
/**
* Recursive insert method
* @param value Value to insert
* @param node Current node
*/
private InsertRec(value: T, node: AVLTreeNode<T>): AVLTreeNode<T>
{
//Bottom reached, return new node
if (node == null)
return new AVLTreeNode<T>(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);
}
Find(item: T): AVLTreeIterator<T>
{
return new AVLTreeIterator(this.FindNode(item));
}
/**
* Return node by inserted value
* @param item
*/
private FindNode(item: T): AVLTreeNode<T>
{
return this.FindRec(item, this.root);
}
/**
* Recursive function for searching
* @param value Value
* @param node Current/Initial node
*/
private FindRec(value: T, node: AVLTreeNode<T>): AVLTreeNode<T>
{
//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;
}
RemoveAt(iterator: AVLTreeIterator<T>): void
{
if (!iterator.HasValue())
return;
this.root = this.DeleteRec(iterator.Value(), this.root);
if (this.root != null)
this.root.parent == null;
}
Remove(item: T): void
{
this.RemoveAt(this.Find(item));
}
/**
* Recursive function sor deleting
* @param value Value to delete
* @param node Current node/Initial node
*/
private DeleteRec(value: T, node: AVLTreeNode<T>): AVLTreeNode<T>
{
//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
let 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);
}
UpdateAt(newValue: T, iterator: AVLTreeIterator<T>): void
{
//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);
}
Update(oldValue: T, newValue: T): void
{
this.UpdateAt(newValue, this.Find(oldValue));
}
//--------------------------------------------------
//---------AT---------------------------------------
//--------------------------------------------------
At(index: number): T
{
return this.AtIterator(index).Value();
}
AtIterator(index: number): AVLTreeIterator<T>
{
//Index out of bounds
if (index > this.Count() - 1 || index < 0)
return new AVLTreeIterator<T>(null);
return new AVLTreeIterator<T>(this.AtRec(index, this.root));
}
/**
* Recursive function for finding nth index
* @param index Index
* @param node Initial/Current node
*/
private AtRec(index: number, node: AVLTreeNode<T>): AVLTreeNode<T>
{
//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----------------------------------
//--------------------------------------------------
FindMin(): AVLTreeIterator<T>
{
return new AVLTreeIterator<T>(this.FindMinRec(this.root));
}
private FindMinRec(node: AVLTreeNode<T>): AVLTreeNode<T>
{
//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);
}
FindMax(): AVLTreeIterator<T>
{
return new AVLTreeIterator<T>(this.FindMaxRec(this.root));
}
private FindMaxRec(node: AVLTreeNode<T>): AVLTreeNode<T>
{
//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-----------------------------------
//--------------------------------------------------
Dispose(): void
{
this.Clear();
this.comparator.Dispose();
}
Clear(): void
{
this.root = null;
}
//--------------------------------------------------
//---------ITERATOR---------------------------------
//--------------------------------------------------
First(): AVLTreeIterator<T>
{
return this.FindMin();
}
Last(): AVLTreeIterator<T>
{
return this.FindMax();
}
//--------------------------------------------------
//---------CLONE------------------------------------
//--------------------------------------------------
Clone(): AVLTree<T>
{
let res = new AVLTree<T>();
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
*/
private CloneRec(node: AVLTreeNode<T>, parent: AVLTreeNode<T> = null): AVLTreeNode<T>
{
if (node == null)
return null;
let res = node.Clone();
res.left = this.CloneRec(res.left, res);
res.right = this.CloneRec(res.right, res);
res.parent = parent;
return res;
}
//--------------------------------------------------
//---------OTHERS-----------------------------------
//--------------------------------------------------
Build(items: T[]): void
{
for (let i = 0; i < items.length; i++)
this.Insert(items[i]);
}
Count(): number
{
if (this.root == null)
return 0;
return this.root.Count();
}
IsEmpty(): boolean
{
return this.Count() == 0;
}
//--------------------------------------------------
//---------ROTATIONS--------------------------------
//--------------------------------------------------
/**
* Rotate a node in left direction
* @param x Node to rotate around
* @returns Higher node in tree hierarchy
*/
protected RotateLeft(x: AVLTreeNode<T>): AVLTreeNode<T>
{
//Check if parent exists
if (x == null || x.right == null)
return null;
//Get all variables
let y = x.right;
let 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
*/
protected RotateRight(y: AVLTreeNode<T>): AVLTreeNode<T>
{
//Check if parent exists
if (y == null || y.left == null)
return null;
//Get all variables
let x = y.left;
let 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
*/
protected RotateLeftRight(x: AVLTreeNode<T>): AVLTreeNode<T>
{
let y = x.left;
let 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
*/
protected RotateRightLeft(x: AVLTreeNode<T>): AVLTreeNode<T>
{
let y = x.right;
let 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
*/
protected RotateAdvisorInsert(node: AVLTreeNode<T>): AVLTreeNode<T>
{
//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
*/
protected RotateAdvisorDelete(node: AVLTreeNode<T>): AVLTreeNode<T>
{
//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;
}
}