AVL Tree
The AVL Tree is one of Binary Search Tree with self balance mechanism. To prevent tree become out of balance, AVL Tree detect the depth of the node and decide whether to balance or not after adding new node.
Three ways to balance
Left rotation
Make the tree rotate to left. Typically happens when the amount of the right children are larger than left, so need to move the node to the left.
Right rotation
Make the tree rotate to right. Typically happens when the amount of the left children are larger than right, so need to move the node to the right.
Double rotation
Before doing the right rotation we need to check the amount of children of left right node is large than the left left node. We need to do left rotation first on the left node, and then do right rotation to self node after that.
In contrast, before doing the left rotation we need to check the amount of children of right left node is large than the right right node. If is larger, we need to do right rotation first at the right node and then do left rotation on self after.
Implementation
class Node {
constructor(value) {
this.value = value
this.left = null
this.right = null
this.height = 1
}
add(value) {
if (this.value > value) {
// go left
if (this.left) {
this.left.add(value)
} else {
this.left = new Node(value)
}
if (!this.right || this.left.height > this.right.height){
this.height = this.left.height + 1
}
} else {
// go right
if (this.right) {
this.right.add(value)
} else {
this.right = new Node(value)
}
if (!this.left || this.right.height > this.left.height){
this.height = this.right.height + 1
}
}
this._balance()
}
_balance() {
const leftHeight = this.left ? this.left.height : 0
const rightHeight = this.right ? this.right.height : 0
if (leftHeight > rightHeight + 1) {
// leftSide balance
const leftLeftHeight = this.left.left ? this.left.left.height : 0
const leftRightHeight = this.left.right ? this.left.right.height : 0
if (leftRightHeight > leftLeftHeight) {
// left rotate
this.left._leftRotate()
}
// right rotate
this._rightRotate()
} else if (rightHeight > leftHeight + 1) {
// rightSide balance
const rightLeftHeight = this.right.left ? this.right.left.height : 0
const rightRightHeight = this.right.right ? this.right.right.height : 0
if (rightLeftHeight > rightRightHeight) {
// right rotate
this.right._rightRotate()
}
// left rotate
this._leftRotate()
}
}
_leftRotate() {
const originRootValue = this.value
const originLeft = this.left
this.value = this.right.value
this.left = this.right
this.right = this.right.right
this.left.value = originRootValue
this.left.right = this.left.left
this.left.left = originLeft
this.left.updateHeight()
this.updateHeight()
}
_rightRotate() {
const origintRootValue = this.value
const originRight = this.right
this.value = this.left.value
this.right = this.left
this.left = this.left.left
this.right.value = origintRootValue
this.right.left = this.right.right
this.right.right = originRight
this.right.updateHeight()
this.updateHeight()
}
updateHeight(){
if (!this.left && !this.right){
this.height = 1
} else if (!this.right || this.left && this.left.height > this.right.height){
this.height = this.left.height + 1
} else if (!this.left || this.right && this.right.height > this.left.height) {
this.height = this.rigth.height + 1
}
}
}
class AVLTree {
constructor() {
this.root = null
this.checkQueue = []
}
add(value) {
const newNode = new Node(value)
if (!this.root) {
this.root = newNode
} else {
this.root.add(value)
}
}
}