Chapter 16: AVL Trees
前言
AVL tree是在每次插入,刪除node時,會注意tree的平衡性。非平衡的BST就是失去BST該有的優異特性,所以不斷保持tree的平衡,就是AVL tree的特色。
大綱
Understanding balance
Perfect balance
"Good-enough" balance
Unbalanced
Implementation
Measuring balance
Rotations
Left rotation
Right rotation
Right-left rotation
Left-right rotation
Balance
Revisiting insertion
Revisiting remove
Understanding balance
首先,我們要給平衡下個定義,怎樣的狀況才叫做平衡。
Perfect balance
The definition of a balanced tree is that every level of the tree must be filled, except for the bottom level.
"Good-enough" balance
The definition of a balanced tree is that every level of the tree must be filled, except for the bottom level
Unbalanced

Measuring balance
balance factor: 左右子樹的高度差不能超過1。
從樹的底端開始向上找起,找到第一個balance factor大於1或小於-1的node,進行調整。
you only need to perform the balancing procedure on the bottom-most node containing the invalid balance factor: the node containing 25

public var height = 0
public var leftHeight: Int {
// 如果沒有左子樹就回傳-1
return leftChild?.height ?? -1
}
public var rightHeight: Int {
// 如果沒有右子樹就回傳-1
return rightChild?.height ?? -1
}
// 用來衡量當前node的左右兩個子樹是否平衡
public var balenceFactor: Int {
return leftHeight - rightHeight
}
Rotations
當遇到沒有平衡的node, 必須經過rotation,讓這個node恢復平衡,根據不平衡的情況,總共有4種rotation狀況。
Left rotation

// Left rotation
private func leftRotate(_ node: AVLNode<Element>) -> AVLNode<Element> {
// pivot經過Left rotation會變成當前的root
let pivot = node.rightChild!
// node是當前的root經過Left rotation其右子樹是原本pivot的左邊
node.rightChild = pivot.leftChild
// pivot變成root後,左子樹為之前的root
pivot.leftChild = node
// 更新經過Left rotation, 前後兩個root的高度
node.height = max(node.leftHeight, node.rightHeight) + 1
pivot.height = max(pivot.leftHeight, pivot.rightHeight) + 1
return pivot
}
Right rotation

// Right rotation
private func rightRotate(_ node: AVLNode<Element>) -> AVLNode<Element> {
let pivot = node.leftChild!
node.leftChild = pivot.rightChild
pivot.rightChild = node
node.height = max(node.leftHeight, node.rightHeight) + 1
pivot.height = max(pivot.leftHeight, pivot.rightHeight) + 1
return pivot
}
Right-left rotation

// Right-left rotation
private func rightLeftRotate(_ node: AVLNode<Element>) -> AVLNode<Element> {
guard let rightChild = node.rightChild else {
return node
}
// 先對當前node的右子樹進行rightRotate
node.rightChild = rightRotate(rightChild)
// 在對當前node為root的整棵樹進行leftRotate
return leftRotate(node)
}
Left-right rotation

// Left-right rotation
private func leftRightRotate(_ node: AVLNode<Element>) -> AVLNode<Element> {
guard let leftChild = node.leftChild else {
return node
}
node.leftChild = leftRotate(leftChild)
return rightRotate(node)
}
Balance
現在已經有上面4種不同rotation方式,接下來就是依據不同情況進行不同的rotaion,讓tree恢復成平衡。
// 進行平衡
private func balence(_ node: AVLNode<Element>) -> AVLNode<Element> {
switch node.balenceFactor {
case 2: // 表示左邊比右邊長
// 判斷要進行哪種rotate
if let leftChild = node.leftChild, leftChild.balenceFactor == -1 {
return leftRotate(node)
} else {
return leftRotate(node)
}
case -2: // 表示右邊比左邊長
if let rightChild = node.rightChild, rightChild.balenceFactor == 1 {
return rightLeftRotate(node)
} else {
return leftRotate(node)
}
default:
// 此node當前是平衡,無需調整
return node
}
}
Revisiting insertion
有了balence的function, 接下就是修改insert fucntion,讓每次插入新的node時都要保持tree平衡。
private func insert(from node: AVLNode<Element>?, value: Element) -> AVLNode<Element> {
guard let node = node else {
return AVLNode(value: value)
}
if value < node.value {
node.leftChild = insert(from: node.leftChild, value: value)
} else {
node.rightChild = insert(from: node.rightChild, value: value)
}
// 檢查插入後當前node是否需要進行平衡動作
let balancedNode = balence(node)
balancedNode.height = max(balancedNode.leftHeight, balancedNode.rightHeight) + 1
return balancedNode
}
Revisiting remove
跟插入一樣類似的動作
private func remove(node: AVLNode<Element>?, value: Element) -> AVLNode<Element>? {
guard let node = node else {
return nil
}
if value == node.value {
if node.leftChild == nil && node.rightChild == nil {
return nil
}
if node.leftChild == nil {
return node.rightChild
}
if node.rightChild == nil {
return node.leftChild
}
node.value = node.rightChild!.min.value
node.rightChild = remove(node: node.rightChild, value: node.value)
} else if value < node.value {
node.leftChild = remove(node: node.leftChild, value: value)
} else {
node.rightChild = remove(node: node.rightChild, value: value)
}
let balancedNode = balence(node)
balancedNode.height = max(balancedNode.leftHeight, balancedNode.rightHeight) + 1
return balancedNode
}
Last updated
Was this helpful?