发布于 

AVL树 | 笔记整理!

AVL树 | 笔记整理!

AVL树

结构体

1
2
3
4
5
6
type AVLNode struct {
key int
left *AVLNode
right *AVLNode
height int
}

定义 AVL 树节点的结构体。每个节点包含一个键值、左子节点、右子节点和当前节点的高度。

辅助函数

newNode 函数用于创建一个新的 AVL 树节点,并初始化键值、左右子节点以及高度。

1
2
3
func newNode(key int) *AVLNode {
return &AVLNode{key: key, left: nil, right: nil, height: 1}
}

getHeight 函数用于获取指定节点的高度。如果节点为空,则返回 0。

1
2
3
4
5
6
func getHeight(node *AVLNode) int {
if node == nil {
return 0
}
return node.height
}

getBalance 函数用于计算指定节点的平衡因子,即左子树的高度减去右子树的高度。如果节点为空,则返回 0。

1
2
3
4
5
6
func getBalance(node *AVLNode) int {
if node == nil {
return 0
}
return getHeight(node.left) - getHeight(node.right)
}

updateHeight 函数用于更新节点的高度。它计算节点的新高度,并将其更新为左右子树中较大的高度加 1。

1
2
3
func updateHeight(node *AVLNode) {
node.height = 1 + max(getHeight(node.left), getHeight(node.right))
}

max 函数用于返回两个整数中较大的值。

1
2
3
4
5
6
func max(a, b int) int {
if a > b {
return a
}
return b
}

findMinValue 函数用于找到以指定节点为根的子树中的最小值节点。它通过不断遍历左子节点,直到找到最左边的叶子节点。

1
2
3
4
5
6
7
func findMinValue(node *AVLNode) *AVLNode {
cur := node
for cur.left != nil {
cur = cur.left
}
return cur
}

printAVLTree 函数用于打印 AVL 树的结构。它采用递归方式,先打印右子树,然后打印当前节点,最后打印左子树。通过增加制表符来表示树的层级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func printAVLTree(node *AVLNode, level int) {
if node == nil {
return
}

printAVLTree(node.right, level+1)

for i := 0; i < level; i++ {
fmt.Print("\t")
}
fmt.Printf("%d\n", node.key)

printAVLTree(node.left, level+1)
}

旋转操作

基础旋转

leftRotate 函数实现左旋操作。它将当前节点的右子节点旋转为当前节点的父节点,并更新节点的高度。

1
2
3
4
5
6
7
8
func leftRotate(node *AVLNode) *AVLNode {
child := node.right
node.right = child.left
child.left = node
updateHeight(node)
updateHeight(child)
return child
}

rightRotate 函数实现右旋操作。它将当前节点的左子节点旋转为当前节点的父节点,并更新节点的高度。

1
2
3
4
5
6
7
8
func rightRotate(node *AVLNode) *AVLNode {
child := node.left
node.left = child.right
child.right = node
updateHeight(node)
updateHeight(child)
return child
}

处理旋转

rotate 函数用于处理 AVL 树中的旋转操作。它检查当前节点的平衡因子,并根据情况执行左旋或右旋操作,以恢复树的平衡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func rotate(node *AVLNode) *AVLNode {
bf := getBalance(node)
//left-right
if bf > 1 {
//LL
if childBf := getBalance(node.left); childBf >= 0 {
return rightRotate(node)
} else {
//LR
node.left = leftRotate(node.left)
return rightRotate(node)
}
}
if bf < -1 {
//RR
if childBf := getBalance(node.right); childBf <= 0 {
return leftRotate(node)
} else {
//RL
node.right = rightRotate(node.right)
return leftRotate(node)
}
}
return node
}

插入

insert 函数用于向 AVL 树中插入一个新节点。它按照二叉搜索树的规则找到合适的位置,并更新节点的高度,然后执行旋转操作以保持树的平衡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 插入
func insert(root *AVLNode, key int) *AVLNode {
if root == nil {
return newNode(key)
}
if key < root.key {
root.left = insert(root.left, key)
} else if key > root.key {
root.right = insert(root.right, key)
} else {
return root
}
updateHeight(root)
return rotate(root)
}

删除

remove 函数用于从 AVL 树中删除指定键值的节点。它按照二叉搜索树的规则找到要删除的节点,并根据情况进行删除操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 删除
// 1. 如果是孤寡人 直接删除
// 2. 如果只有一个孩子 孩子称为大爹 即可
// 3. 如果有两个孩子 将左边孩子中最大的复制给要删除的 然后删除最大的孩子 或者将右边孩子中最小的复制给要删除的 然后删除最小的孩子
func remove(root *AVLNode, key int) *AVLNode {
if root == nil {
return root
}
if key < root.key {
root.left = remove(root.left, key)
} else if key > root.key {
root.right = remove(root.right, key)
} else {
if root.left == nil || root.right == nil {
child := root.left
if root.right != nil {
child = root.right
}
if child == nil {
return nil
} else {
root = child
}
} else {
cur := findMinValue(root.right)
root.right = remove(root.right, cur.key)
root.key = cur.key
}
}
updateHeight(root)
return rotate(root)
}

测试代码

一个简单的测试代码,它演示了如何使用 AVL 树的插入和删除操作,并打印树的结构。首先,将一些节点插入树中,然后删除一些节点,并输出删除后的树结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func main() {
var root *AVLNode

// 插入节点
root = insert(root, 10)
root = insert(root, 20)
root = insert(root, 30)
root = insert(root, 40)
root = insert(root, 50)
root = insert(root, 25)

// 输出插入节点后的树结构
fmt.Println("插入节点后的树结构:")
printAVLTree(root, 0)

// 删除节点
root = remove(root, 30)
root = remove(root, 40)

// 输出删除节点后的树结构
fmt.Println("删除节点后的树结构:")
printAVLTree(root, 0)
}