parent | node / \ left node right node
The cost of operations(Search, delete ...) may become O(n) for a skewed BST
x \ y \ z ....
If we make sure that the height of the tree remains O(log(n)) after every insertion and deletion, then we can guarantee an upper bound of O(log(n)) for all these operations. The height of an AVL tree is always O(log(n)) where n is the number of nodes in the tree.
-2 < height(left) - height(right) < 2
A <- skew(A) = 1 - 3 = -2 (skewed BST) / \ B C <- skew(C) = 1 - 2 = -1 / \ D E \ "F" <- new insertion How to re-balancing the BST? left rotate C <- skew(C) = 2 - 2 = 0 / \ A E / \ \ B D F traversal: before: B, A, D, C, E, F After: B, A, D, C, E, F Case 2: A <- skew(A) = 1 - 3 = -2 (skewed BST) / \ B C <- skew(C) = 1 - 2 = 1 / \ D E / "F" <- new insertion How to re-balancing the BST? step1: rotateRight(C) A / \ B D / \ F C \ E step2: rotateLeft(A) D <- skew(C) = 2 - 2 = 0 / \ A C / \ \ B F E traversal: before: B, A, F, D, C, E After: B, A, F, D, C, E
func BuildAVL(root *Node, value int) *Node { if root == nil { return &Node{value: value, size: 1} // place node to the leaf } if value > root.value { root.right = BuildAVL(root.right, value) root.right.parent = root } if value < root.value { root.left = BuildAVL(root.left, value) root.left.parent = root } // calculate the height of the root root.size = 1 + util.Max(height(root.right), height(root.left)) // re-balancing the tree, and return the new root return root.balancing() }
func (node *Node) balancing() *Node { skew := node.skew() // still balance if skew < 2 && skew > -2 { return node } // right left rotate if skew == -2 && node.right.skew() == 1 { node.right = node.right.rotateRight() return node.rotateLeft() } // left rotate if skew == -2 && node.right.skew() == -1 { return node.rotateLeft() } // right rotate if skew == 2 && node.left.skew() == 1 { return node.rotateRight() } // left right rotate if skew == 2 && node.left.skew() == -1 { node.left = node.left.rotateLeft() return node.rotateRight() } return node }
A <- height = 4 / \ B C <- height = 3 / \ h:1 -> D E <- height = 2 \ "F" <- <- height = 1 C <- height = 3 / \ height = 2 -> A E <- height = 2 / \ \ B D F we only need to update the node and its parent till reach the root
func (node *Node) updating() { if node == nil { return } node.size = 1 + util.Max(height(node.right), height(node.left)) if node.parent != nil { node.parent.updating() } }
// skew(node): height(node.left) - height(node.right) => {-1, 0, +1} func (node *Node) skew() int { return height(node.left) - height(node.right) }
func (node *Node) rotateLeft() *Node { newRoot := node.right children := newRoot.left node.right = children newRoot.left = node newRoot.parent = node.parent if children != nil { children.parent = node } node.parent = newRoot node.updating() return newRoot }
func (node *Node) rotateRight() *Node { newRoot := node.left children := newRoot.right node.left = children newRoot.right = node newRoot.parent = node.parent if children != nil { children.parent = node } node.parent = newRoot node.updating() return newRoot }