插入
若向平衡二叉树中
插入一个新结点后破坏了平衡二叉树的平衡性。首先要找出插入新结点后失去平衡的根结点的指针
最小子树
。然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。当失去平衡的最小子树被调整为平衡子树后,
原有其他所有不平衡子树无需调整
,整个二叉排序树就又成为一棵平衡二叉树。失去平衡的最小子树是指以离插入结点最近,且平衡因子绝对值大于 1 的结点作为根的子树。假设用 A 表示失去平衡的最小子树的根结点,则调整该子树的操作可归纳为下列四种情况。
插入方式:跟查找二叉树一样的方式插入一个新的节点。(一直找到叶子处,新节点挂在旧叶子下)
平衡查找:构造完新的查找树之后,比较过的节点为根的子树都要验证是不是还平衡,如果不平衡的话,需要平衡化。
平衡校验:增加一个节点的高度,heigh = (max(leftHeigh) > max(rightHeight)?max(leftHeigh) :max(rightHeight))+1,
校验是不是超过1了。
平衡化方式:旋转,方式如下:
( 1 ) RR 型平衡旋转法
由于在 A 的左孩子 B 的左子树上插入结点 F ,使 A 的平衡因子由 1 增至 2 而失去平衡。故需进行一次顺时针旋转操作。 即将 A 的左孩子 B 向右上旋转代替 A 作为根结点, A 向右下旋转成为 B 的右子树的根结点。而原来 B 的右子树则变成 A 的左子树。
( 2 ) LL 型平衡旋转法
由于在 A 的右孩子 C 的右子树上插入结点 F ,使 A 的平衡因子由 -1 减至 -2 而失去平衡。故需进行一次逆时针旋转操作。即将 A的右孩子 C 向左上旋转代替 A 作为根结点, A 向左下旋转成为 C 的左子树的根结点。而原来 C 的左子树则变成 A 的右子树。
( 3 ) LR 型平衡旋转法
由于在 A 的左孩子 B 的右子数上插入结点 F ,使 A 的平衡因子由 1 增至 2 而失去平衡。故需进行两次旋转操作(先逆时针,后顺时针)。即先将 A 结点的左孩子 B 的右子树的根结点 D 向左上旋转提升到 B 结点的位置,然后再把该 D 结点向右上旋转提升到 A 结点的位置。即先使之成为 LL 型,再按 LL 型处理 。
如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到 A 的左子树上,此时成为 LL 型,再按 LL 型处理成平衡型。
( 4 ) RL 型平衡旋转法
由于在 A 的右孩子 C 的左子树上插入结点 F ,使 A 的平衡因子由 -1 减至 -2 而失去平衡。故需进行两次旋转操作(先顺时针,后逆时针),即先将 A 结点的右孩子 C 的左子树的根结点 D 向右上旋转提升到 C 结点的位置,然后再把该 D 结点向左上旋转提升到 A 结点的位置。即先使之成为 RR 型,再按 RR 型处理。
如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到 A 的左子树上,此时成为 RR 型,再按 RR 型处理成平衡型。
平衡化靠的是旋转。 参与旋转的是 3 个节点(其中一个可能是外部节点 NULL ),旋转就是把这 3 个节点转个位置。注意的是,左旋的时候 p->right 一定不为空,右旋的时候 p->left 一定不为空,这是显而易见的。
如果从空树开始建立,并时刻保持平衡,那么不平衡只会发生在插入删除操作上,而不平衡的标志就是出现 bf == 2 或者 bf == -2的节点。
删除
在删除的时候,同样会导致平衡二叉树失衡。
1.删除方式:先查找到对应的节点,删除
2.树的连续性保证:跟查找树一样的方式
2.1.如果被删除的子树只有一个节点,那么把该节点替换删除的节点
2.2.如果就是一个叶子,直接删除
2.3.删除节点又有左节点,又有右子树。那么要么找出右子树的最小节点或者找出左子树的最大节点替换被删除的节点。
2.4.删除之后,同样要检查是不是保持平衡。
平衡二叉树的插入和删除的代码实现
AvlTree.h
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 #pragma once 5 6 //平衡二叉树结点 7 template <typename T> 8 struct AvlNode 9 { 10 T data; 11 int height; //结点所在高度,校验平衡度 12 AvlNode<T> *left; 13 AvlNode<T> *right; 14 AvlNode<T>(const T theData) : data(theData), left(NULL), right(NULL), height(0){} 15 }; 16 17 //AvlTree 18 template <typename T> 19 class AvlTree 20 { 21 public: 22 AvlTree<T>(){} 23 ~AvlTree<T>(){} 24 AvlNode<T> *root; 25 //插入结点 26 void Insert(AvlNode<T> *&t, T x); 27 //删除结点 28 bool Delete(AvlNode<T> *&t, T x); 29 //查找是否存在给定值的结点 30 bool Contains(AvlNode<T> *t, const T x) const; 31 //中序遍历 32 void InorderTraversal(AvlNode<T> *t); 33 //前序遍历 34 void PreorderTraversal(AvlNode<T> *t); 35 //最小值结点 36 AvlNode<T> *FindMin(AvlNode<T> *t) const; 37 //最大值结点 38 AvlNode<T> *FindMax(AvlNode<T> *t) const; 39 private: 40 //求树的高度 41 int GetHeight(AvlNode<T> *t); 42 //单旋转 左 43 AvlNode<T> *LL(AvlNode<T> *t); 44 //单旋转 右 45 AvlNode<T> *RR(AvlNode<T> *t); 46 //双旋转 右左 47 AvlNode<T> *LR(AvlNode<T> *t); 48 //双旋转 左右 49 AvlNode<T> *RL(AvlNode<T> *t); 50 }; 51 52 template <typename T> 53 AvlNode<T> * AvlTree<T>::FindMax(AvlNode<T> *t) const 54 { 55 if (t == NULL) 56 return NULL; 57 if (t->right == NULL) 58 return t; 59 return FindMax(t->right); 60 } 61 62 template <typename T> 63 AvlNode<T> * AvlTree<T>::FindMin(AvlNode<T> *t) const 64 { 65 if (t == NULL) 66 return NULL; 67 if (t->left == NULL) 68 return t; 69 return FindMin(t->left); 70 } 71 72 73 template <typename T> 74 int AvlTree<T>::GetHeight(AvlNode<T> *t) 75 { 76 if (t == NULL) 77 return -1; 78 else 79 return t->height; 80 } 81 82 83 //单旋转 84 //左左插入导致的不平衡 85 template <typename T> 86 AvlNode<T> * AvlTree<T>::LL(AvlNode<T> *t) 87 { 88 AvlNode<T> *q = t->left; 89 t->left = q->right; 90 q->right = t; 91 t = q; 92 t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; 93 q->height = max(GetHeight(q->left), GetHeight(q->right)) + 1; 94 return q; 95 } 96 97 //单旋转 98 //右右插入导致的不平衡 99 template <typename T> 100 AvlNode<T> * AvlTree<T>::RR(AvlNode<T> *t) 101 { 102 AvlNode<T> *q = t->right; 103 t->right = q->left; 104 q->left = t; 105 t = q; 106 t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; 107 q->height = max(GetHeight(q->left), GetHeight(q->right)) + 1; 108 return q; 109 } 110 111 //双旋转 112 //插入点位于t的左儿子的右子树 113 template <typename T> 114 AvlNode<T> * AvlTree<T>::LR(AvlNode<T> *t) 115 { 116 //双旋转可以通过两次单旋转实现 117 //对t的左结点进行RR旋转,再对根节点进行LL旋转 118 RR(t->left); 119 return LL(t); 120 } 121 122 //双旋转 123 //插入点位于t的右儿子的左子树 124 template <typename T> 125 AvlNode<T> * AvlTree<T>::RL(AvlNode<T> *t) 126 { 127 LL(t->right); 128 return RR(t); 129 } 130 131 132 template <typename T> 133 void AvlTree<T>::Insert(AvlNode<T> *&t, T x) 134 { 135 if (t == NULL) 136 t = new AvlNode<T>(x); 137 else if (x < t->data) 138 { 139 Insert(t->left, x); 140 //判断平衡情况 141 if (GetHeight(t->left) - GetHeight(t->right) > 1) 142 { 143 //分两种情况 左左或左右 144 145 if (x < t->left->data)//左左 146 t = LL(t); 147 else //左右 148 t = LR(t); 149 } 150 } 151 else if (x > t->data) 152 { 153 Insert(t->right, x); 154 if (GetHeight(t->right) - GetHeight(t->left) > 1) 155 { 156 if (x > t->right->data) 157 t = RR(t); 158 else 159 t = RL(t); 160 } 161 } 162 else 163 ;//数据重复 164 t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; 165 } 166 167 template <typename T> 168 bool AvlTree<T>::Delete(AvlNode<T> *&t, T x) 169 { 170 //t为空 未找到要删除的结点 171 if (t == NULL) 172 return false; 173 //找到了要删除的结点 174 else if (t->data == x) 175 { 176 //左右子树都非空 177 if (t->left != NULL && t->right != NULL) 178 {//在高度更大的那个子树上进行删除操作 179 180 //左子树高度大,删除左子树中值最大的结点,将其赋给根结点 181 if (GetHeight(t->left) > GetHeight(t->right)) 182 { 183 t->data = FindMax(t->left)->data; 184 Delete(t->left, t->data); 185 } 186 else//右子树高度更大,删除右子树中值最小的结点,将其赋给根结点 187 { 188 t->data = FindMin(t->right)->data; 189 Delete(t->right, t->data); 190 } 191 } 192 else 193 {//左右子树有一个不为空,直接用需要删除的结点的子结点替换即可 194 AvlNode<T> *old = t; 195 t = t->left ? t->left: t->right;//t赋值为不空的子结点 196 delete old; 197 } 198 } 199 else if (x < t->data)//要删除的结点在左子树上 200 { 201 //递归删除左子树上的结点 202 Delete(t->left, x); 203 //判断是否仍然满足平衡条件 204 if (GetHeight(t->right) - GetHeight(t->left) > 1) 205 { 206 if (GetHeight(t->right->left) > GetHeight(t->right->right)) 207 { 208 //RL双旋转 209 t = RL(t); 210 } 211 else 212 {//RR单旋转 213 t = RR(t); 214 } 215 } 216 else//满足平衡条件 调整高度信息 217 { 218 t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; 219 } 220 } 221 else//要删除的结点在右子树上 222 { 223 //递归删除右子树结点 224 Delete(t->right, x); 225 //判断平衡情况 226 if (GetHeight(t->left) - GetHeight(t->right) > 1) 227 { 228 if (GetHeight(t->left->right) > GetHeight(t->left->left)) 229 { 230 //LR双旋转 231 t = LR(t); 232 } 233 else 234 { 235 //LL单旋转 236 t = LL(t); 237 } 238 } 239 else//满足平衡性 调整高度 240 { 241 t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1; 242 } 243 } 244 245 return true; 246 } 247 248 //查找结点 249 template <typename T> 250 bool AvlTree<T>::Contains(AvlNode<T> *t, const T x) const 251 { 252 if (t == NULL) 253 return false; 254 if (x < t->data) 255 return Contains(t->left, x); 256 else if (x > t->data) 257 return Contains(t->right, x); 258 else 259 return true; 260 } 261 262 //中序遍历 263 template <typename T> 264 void AvlTree<T>::InorderTraversal(AvlNode<T> *t) 265 { 266 if (t) 267 { 268 InorderTraversal(t->left); 269 cout << t->data << ' '; 270 InorderTraversal(t->right); 271 } 272 } 273 274 //前序遍历 275 template <typename T> 276 void AvlTree<T>::PreorderTraversal(AvlNode<T> *t) 277 { 278 if (t) 279 { 280 cout << t->data << ' '; 281 PreorderTraversal(t->left); 282 PreorderTraversal(t->right); 283 } 284 }
main.cpp
1 #include "AvlTree.h" 2 3 int main() 4 { 5 AvlTree<int> tree; 6 int value; 7 int tmp; 8 cout << "请输入整数建立二叉树(-1结束):" << endl; 9 while (cin >> value) 10 { 11 if (value == -1) 12 break; 13 tree.Insert(tree.root,value); 14 } 15 cout << "中序遍历"; 16 tree.InorderTraversal(tree.root); 17 cout << "\n前序遍历:"; 18 tree.PreorderTraversal(tree.root); 19 cout << "\n请输入要查找的结点:"; 20 cin >> tmp; 21 if (tree.Contains(tree.root, tmp)) 22 cout << "已查找到" << endl; 23 else 24 cout << "值为" << tmp << "的结点不存在" << endl; 25 cout << "请输入要删除的结点:"; 26 cin >> tmp; 27 tree.Delete(tree.root, tmp); 28 cout << "删除后的中序遍历:"; 29 tree.InorderTraversal(tree.root); 30 cout << "\n删除后的前序遍历:"; 31 tree.PreorderTraversal(tree.root); 32 }
测试结果: