平衡二叉树的平衡实现--插入、删除

插入

     若向平衡二叉树中 插入一个新结点后破坏了平衡二叉树的平衡性。首先要找出插入新结点后失去平衡的根结点的指针 最小子树 。然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。当失去平衡的最小子树被调整为平衡子树后, 原有其他所有不平衡子树无需调整 ,整个二叉排序树就又成为一棵平衡二叉树。失去平衡的最小子树是指以离插入结点最近,且平衡因子绝对值大于 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 }
复制代码

 

测试结果:


    

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
平衡二叉树是一种特殊的二叉搜索树,它能够保证在最坏情况下的间复杂度为 O(log n)。常见的平衡二叉树有 AVL 树、红黑树等。 平衡二叉树插入删除操作都需要保持树的平衡性。以下以 AVL 树为例说明。 AVL 树是一种带有平衡条件的二叉搜索树,它要求所有节点的左右子树高度差不超过 1。插入删除节点,需要通过旋转操作来保持平衡。 1. 插入节点 插入节点,首先按照二叉搜索树的规则将节点插入到树中。然后从插入节点的父节点开始,向上遍历直到根节点,检查每个节点是否平衡,如果不平衡,需要进行旋转操作来重新平衡。 a. 左旋转(LL) 当插入节点导致节点的左子树高度比右子树高度大 2 ,需要进行左旋转。左旋转的过程如下: 1) 将节点的右子节点的左子树挂到节点的右子节点的左子树上; 2) 将节点的右子节点替换为原右子节点的左子节点; 3) 将节点的父节点指向原右子节点; 4) 将原右子节点的左子节点指向节点。 b. 右旋转(RR) 当插入节点导致节点的右子树高度比左子树高度大 2 ,需要进行右旋转。右旋转的过程如下: 1) 将节点的左子节点的右子树挂到节点的左子节点的右子树上; 2) 将节点的左子节点替换为原左子节点的右子节点; 3) 将节点的父节点指向原左子节点; 4) 将原左子节点的右子节点指向节点。 c. 先右旋转后左旋转(RL) 当插入节点导致节点的右子树高度比左子树高度大 1,且节点的右子节点的左子树高度比右子树高度大 1 ,需要进行先右旋转后左旋转。先右旋转后左旋转的过程如下: 1) 对节点的右子节点进行右旋转; 2) 对节点进行左旋转。 d. 先左旋转后右旋转(LR) 当插入节点导致节点的左子树高度比右子树高度大 1,且节点的左子节点的右子树高度比左子树高度大 1 ,需要进行先左旋转后右旋转。先左旋转后右旋转的过程如下: 1) 对节点的左子节点进行左旋转; 2) 对节点进行右旋转。 2. 删除节点 删除节点,首先按照二叉搜索树的规则将节点从树中删除。然后从删除节点的父节点开始,向上遍历直到根节点,检查每个节点是否平衡,如果不平衡,需要进行旋转操作来重新平衡。 a. 左旋转(LL) 当删除节点导致节点的左子树高度比右子树高度大 2 ,需要进行左旋转。左旋转的过程与插入节点的左旋转相同。 b. 右旋转(RR) 当删除节点导致节点的右子树高度比左子树高度大 2 ,需要进行右旋转。右旋转的过程与插入节点的右旋转相同。 c. 先右旋转后左旋转(RL) 当删除节点导致节点的右子树高度比左子树高度大 1,且节点的右子节点的左子树高度比右子树高度大 1 ,需要进行先右旋转后左旋转。先右旋转后左旋转的过程与插入节点的先右旋转后左旋转相同。 d. 先左旋转后右旋转(LR) 当删除节点导致节点的左子树高度比右子树高度大 1,且节点的左子节点的右子树高度比左子树高度大 1 ,需要进行先左旋转后右旋转。先左旋转后右旋转的过程与插入节点的先左旋转后右旋转相同。 以上就是平衡二叉树插入删除操作,通过旋转操作可以保证树的平衡性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值