平衡二叉树的调整(左旋与右旋)
平衡二叉树
平衡二叉树(Balanced Binary Tree)是一种特殊的二叉树,它在结构上保持一定的平衡,以确保在最坏情况下依然具有较好的查找、插入和删除性能。
平衡二叉树的定义
平衡的具体定义可以根据不同类型的平衡树略有不同。一般来说,一个二叉树是平衡的,当其任意节点的左右子树高度差的绝对值不超过某个特定值(通常是1)时。
常见类型的平衡二叉树
AVL树:
每个节点的左右子树高度差(平衡因子)只允许为 -1、0 或 1。
在插入或删除节点后,如果导致不平衡,会通过旋转操作来恢复平衡。
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139#include <iostream>
#include <algorithm> // 用于 std::max
using namespace std;
// 节点结构
struct Node {
int key; // 节点值
Node* left; // 左子节点
Node* right; // 右子节点
int height; // 节点高度
Node(int k) : key(k), left(nullptr), right(nullptr), height(1) {} // 初始化节点
};
// 获取节点的高度
int getHeight(Node* node) {
return node ? node->height : 0;
}
// 获取平衡因子
int getBalanceFactor(Node* node) {
return node ? getHeight(node->left) - getHeight(node->right) : 0;
}
// 更新节点的高度
void updateHeight(Node* node) {
node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
}
// 右旋操作
Node* rightRotate(Node* y) {
Node* x = y->left;
Node* T2 = x->right;
// 右旋转
x->right = y;
y->left = T2;
// 更新高度
updateHeight(y);
updateHeight(x);
// 返回新的根节点
return x;
}
// 左旋操作
Node* leftRotate(Node* x) {
Node* y = x->right;
Node* T2 = y->left;
// 左旋转
y->left = x;
x->right = T2;
// 更新高度
updateHeight(x);
updateHeight(y);
// 返回新的根节点
return y;
}
// 插入节点并保持平衡
Node* insert(Node* node, int key) {
// 1. 标准的二叉搜索树插入
if (!node) return new Node(key);
if (key < node->key) {
node->left = insert(node->left, key);
} else if (key > node->key) {
node->right = insert(node->right, key);
} else {
// 不允许插入重复值
return node;
}
// 2. 更新当前节点的高度
updateHeight(node);
// 3. 计算平衡因子
int balanceFactor = getBalanceFactor(node);
// 4. 根据平衡因子进行相应的旋转操作
// 左左情况
if (balanceFactor > 1 && key < node->left->key) {
return rightRotate(node);
}
// 右右情况
if (balanceFactor < -1 && key > node->right->key) {
return leftRotate(node);
}
// 左右情况
if (balanceFactor > 1 && key > node->left->key) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// 右左情况
if (balanceFactor < -1 && key < node->right->key) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
// 返回不变的节点指针
return node;
}
// 中序遍历树以显示结果
void inOrder(Node* root) {
if (root) {
inOrder(root->left);
cout << root->key << " ";
inOrder(root->right);
}
}
// 主函数测试AVL树
int main() {
Node* root = nullptr;
// 插入一些节点
root = insert(root, 10);
root = insert(root, 20);
root = insert(root, 30);
root = insert(root, 40);
root = insert(root, 50);
root = insert(root, 25);
// 中序遍历 AVL 树
cout << "中序遍历 AVL 树: ";
inOrder(root);
cout << endl;
return 0;
}
红黑树:
- 是一种自平衡的二叉搜索树,每个节点都有一个颜色属性(红色或黑色),并遵循特定的颜色规则。
- 保证从根到叶的路径上的黑色节点数量相同,从而保持树的平衡性。
平衡二叉树的特点
时间复杂度:
- 查找、插入和删除操作的时间复杂度通常为 O(\log n),这使得平衡二叉树非常高效,特别是在大量数据的情况下。
空间复杂度:
- 平衡二叉树的空间复杂度为 O(n),与普通的二叉树相同。
自我平衡:
- 在插入或删除节点时,通过旋转和调整树的结构,保持树的平衡,从而避免退化成链表。
旋转操作是平衡二叉树(如 AVL 树和红黑树)中的重要技术,用于在插入或删除节点后恢复树的平衡。旋转操作可以分为两种类型:左旋(Left Rotation)和右旋(Right Rotation)。以下是这两种旋转的详细介绍及其实现。
平衡二叉树的调整
首先注意,右旋(L)实际上是将树向左旋转,左旋则是将树向右旋转
1. 右旋(Right Rotation)
右旋操作是将某个节点(称为“失衡节点”)的左子节点提升为新的根节点,同时将失衡节点降为新根节点的右子节点。
右旋的步骤
- 设失衡节点为
y
,其左子节点为x
。 - 将
x
的右子节点(如果存在)连接到y
的左子节点。 - 将
x
提升为新的根节点。 - 将
y
设为x
的右子节点。
右旋的伪代码
1 | struct TreeNode { |
2. 左旋(Left Rotation)
左旋操作是将某个节点的右子节点提升为新的根节点,同时将失衡节点降为新根节点的左子节点。
左旋的步骤
- 设失衡节点为
x
,其右子节点为y
。 - 将
y
的左子节点(如果存在)连接到x
的右子节点。 - 将
y
提升为新的根节点。 - 将
x
设为y
的左子节点。
左旋的伪代码
1 | // 左旋操作 |
3. 组合旋转
AVL有且只有的四种情况(LL,LR,RL,RR)
图片来自数据结构之AVL树(平衡二叉树)的理解_avl左右旋-CSDN博客
1.LL
2.LR
3.RL
4.RR
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Comments