class AVLTree extends BinarySearchTree {
constructor (...args) {
super (...args);
this.updateHeight ()
}
updateHeight () {
this.height = this.node ? Math.max(this.node.left.height, this.node.right.height) + 1 : -1
}
get balanceFactor () {
if (this.node) return this.node.right.height - this.node.left.height
return 0
}
findAndModify (key, modify) {
let result;
if (!this.node || this.node.entry.key == key) {
result = modify (this);
} else if (this.node.entry.key < key) {
result = this.node.right.findAndModify(key, modify);
} else {
result = this.node.left.findAndModify (key, modify);
}
this.rebalance()
}
rebalance () {
this.updateHeight ();
let bal = this.balanceFactor;
if (bal < -1) {
if (this.node.left.node.left.height < this.node.left.node.right.height)
this.node.left.rotateLeft();
this.rotateRight();
}
else if (bal > +1) {
if (this.node.right.node.left.height > this.node.right.node.right.height)
this.node.right.rotateRight();
this.rotateLeft();
}
}
rotateRight () {
let [d, b, C] = [this.node, this.node.left.node, this.node.left.node.right.node];
[this.node, b.right.node, d.left.node] = [b, d, C];
d.left.updateHeight();
b.right.updateHeight();
this.updateHeight();
}
rotateLeft () {
let [b, d, C] = [this.node, this.node.right.node, this.node.right.node.left.node];
[this.node, d.left.node, b.right.node] = [d, b, C];
b.right.updateHeight();
d.left.updateHeight();
this.updateHeight();
}
insert (entry) {
let insertModifier = (t) => {
if (t.node) throw `This key already in tree: ${entry.key}`;
t.node = new BinaryTreeNode (entry, new AVLTree(), new AVLTree())
return true;
}
return this.findAndModify (entry.key, insertModifier)
}
findAndDelete (key) {
let deleteModifier = (t) => {
t.delete()
}
return this.findAndModify (key, deleteModifier)
}
delete () {
super.delete()
this.rebalance()
}
clone() {
if (!this.node) return new AVLTree();
return new AVLTree (new BinaryTreeNode (this.node.entry,
this.node.left.clone(),
this.node.right.clone()))
}
}