0%

平衡二叉树

二叉排序树

有关二叉排序树的概念与操作,移步Hear

平衡二叉树概念

  • 特殊类型的二叉排序树。二叉排序树的查找性能取决于二叉树的结构。树的高度越小,查找速度越快。

注意:如果连二叉排序树都不是,那肯定不是平衡二叉树。

  • 如果非空,左子树与右子树深度之差的绝对值不超过1.
  • 左子树与右子树也是平衡二叉树。

结点定义

它基本和二叉排序树差不多,就是多了个记录结点高度(用来计算平衡因子)的字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef int KeyType;
typedef int OtherInfo;

//----------二叉排序树存储表示-----------
typedef struct{
KeyType key; //关键字项
OtherInfo info; //其他数据信息

}ElemType;

typedef struct BSTNode {
ElemType data; //每个结点的数据域包括关键字项和其他信息
struct BSTNode *lchild;
struct BSTNode *rchild;
int nHeight; /*树的高度,可以计算平衡因子*/
} BSTNode,*BSTree;

平衡二叉树的操作

  • 查找

  • 插入

  • 创建

  • 删除

    以上操作和二叉排序树一样,主要区别在于插入过程中如果发现插入破坏了平衡需要调整。下面重点说一说怎么调整(旋转)。

平衡二叉树的平衡调整方法

  • LL型

    指插入以A为根的左子树的左子树上破坏了平衡。
    在这里插入图片描述
    插入7或10之后53的平衡因子变为2,高了,怎么降低?那就是把高的转下来(顺时针)。主要就是 根和图中三角形那 发生了变化。三角形那可以为空。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    static BSTree SingleRotateWithLeft(BSTree pNode)	//LL型 
    {
    BSTNode *pNode1;

    pNode1 = pNode->lchild; //图中9
    pNode->lchild = pNode1->rchild;
    pNode1->rchild = pNode;

    /*结点的位置变了, 要更新结点的高度值*/
    pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
    pNode1->nHeight = Max(Height(pNode1->lchild), pNode->nHeight) + 1;

    return pNode1;
    }
    • RR型

      指插入以A为根的右子树的右子树上破坏了平衡。
      在这里插入图片描述
      插入58或70之后17的平衡因子变为-2,高了,怎么降低?那就是把高的转下来(逆时针)。主要就是 根和图中三角形那 发生了变化。三角形那可以为空。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      static BSTree SingleRotateWithRight(BSTree pNode)			//RR型
      {
      BSTNode *pNode1;

      pNode1 = pNode->rchild; //图中53
      pNode->rchild = pNode1->lchild;
      pNode1->lchild = pNode;

      /*结点的位置变了, 要更新结点的高度值*/
      pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
      pNode1->nHeight = Max(Height(pNode1->rchild), pNode->nHeight) + 1;

      return pNode1;
      }

      返回顶部

    • LR型

      指插入以A为根的左子树的右子树上破坏了平衡。
      在这里插入图片描述
      插入25或35之后53的平衡因子为2,需要旋转,一步不能解决,那就转两次。
      先把53的左子树进行RR型旋转,得到中间图,再把中间图进行LL型旋转即可。

      1
      2
      3
      4
      5
      6
      static BSTree DoubleRotateWithLeft(BSTree pNode)		//LR型
      {
      pNode->lchild = SingleRotateWithRight(pNode->lchild);

      return SingleRotateWithLeft(pNode);
      }
    • RL型

      指插入以A为根的右子树的左子树中破坏了平衡。
      在这里插入图片描述
      插入55或59之后53的平衡因子为-2,需要旋转,一步不能解决,那就转两次。
      先把53的右子树进行LL型旋转,得到中间图,再把中间图进行RR型旋转即可。

      1
      2
      3
      4
      5
      6
      static BSTree DoubleRotateWithRight(BSTree pNode)
      {
      pNode->rchild = SingleRotateWithLeft(pNode->rchild); //RL型

      return SingleRotateWithRight(pNode);
      }

      返回顶部

      总的代码:

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#include <iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;

#define Max(a,b) ((a)>(b)?(a):(b))

typedef int KeyType;
typedef int OtherInfo;

//----------二叉排序树存储表示-----------
typedef struct{
KeyType key; //关键字项
OtherInfo info; //其他数据信息

}ElemType;

typedef struct BSTNode {
ElemType data; //每个结点的数据域包括关键字项和其他信息
struct BSTNode *lchild;
struct BSTNode *rchild;
int nHeight; /*树的高度,可以计算平衡因子*/
} BSTNode,*BSTree;


void InsertBST(BSTree &T,ElemType e); /*插入操作*/
BSTree SearchBST(BSTree T,KeyType key); /*查找操作*/
bool delete_BSTree(BSTree &T,int key); /*删除操作*/

/*打印操作*/
void PreOrder(BSTree T); //递归先序遍历
void InOrder(BSTree T); //递归中序遍历

static int Height(BSTree pNode);

/*旋转操作*/
static BSTree SingleRotateWithLeft(BSTree pNode);
static BSTree SingleRotateWithRight(BSTree pNode);
static BSTree DoubleRotateWithLeft(BSTree pNode);
static BSTree DoubleRotateWithRight(BSTree pNode);

void PreOrder(BSTree T){//递归先序遍历
if(T!=NULL){
cout<<T->data.key<<" ";
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}

void InOrder(BSTree T){//递归中序遍历
if(T!=NULL){
InOrder(T->lchild);
cout<<T->data.key<<" ";
InOrder(T->rchild);
}
}

BSTree SearchBST(BSTree T,KeyType key) {
if ((!T) || key == T->data.key)
return T;
else if (key < T->data.key)
return SearchBST(T->lchild, key);
else return SearchBST(T->rchild, key);
}

/*得到节点的高度以计算平衡因子*/
static int Height(BSTree pNode)
{
if (NULL == pNode)
return 0;
return pNode->nHeight;
}

void InsertBST(BSTree &T,ElemType e)
{
if(!T){ //找到插入位置
BSTree S=new BSTNode; //新节点保存数据
S->data=e;
S->nHeight = 0;
S->lchild=S->rchild=NULL;
T=S; //把新结点放到已找到的插入位置
}
else if(e.key < T->data.key){
InsertBST(T->lchild,e);

if (Height(T->lchild) - Height(T->rchild) == 2) /*AVL树不平衡*/
{
cout<<"因为"<<T->data.key<<"左孩子高度"<<Height(T->lchild);
cout<<"大于右孩子高度"<<Height(T->rchild)<<endl;
if (e.key < T->lchild->data.key)
{ /*插入到了左子树左边, 做单旋转*/
cout<<"发生LL型旋转"<<endl;
T = SingleRotateWithLeft(T);
}
else
{ /*插入到了左子树右边, 做双旋转*/
cout<<"发生LR型旋转"<<endl;
T = DoubleRotateWithLeft(T);
}
}
}
else if(e.key > T->data.key) {

InsertBST(T->rchild,e);
if (Height(T->rchild) - Height(T->lchild) == 2) /*AVL树不平衡*/
{
cout<<"因为"<<T->data.key<<"左孩子高度"<<Height(T->lchild);
cout<<"小于右孩子高度"<<Height(T->rchild)<<endl;
if (e.key > T->rchild->data.key)
{ /*插入到了右子树右边, 做单旋转*/
cout<<"发生RL旋转"<<endl;
T = SingleRotateWithRight(T);
}
else
{ /*插入到了右子树左边, 做双旋转*/
cout<<"发生RR旋转"<<endl;
T = DoubleRotateWithRight(T);
}
}
}
else{
cout<<"已有此值~"<<endl;
return;
}
T->nHeight = Max(Height(T->lchild), Height(T->rchild)) + 1;
}

void delete_Node1(BSTree &p)
{
BSTree q,s;
if(!p->lchild) //由于这个if在前面,所以左右子树均为空的情况会在这里处理
{ //如果左子树为空,则只需重接其右子树
q = p;
p = p->rchild ;
free(q);
}
else if(!p->rchild)
{ //如果右子树为空,则只需重接其左子树
q = p;
p = p->lchild;
free(q);
}
else
{ //如果左右子树都不为空,这里采取修改左子树的方法,也可以修改右子树,方法类似
s = p->lchild; //取待删节点的左孩子结点

while(s->rchild) //找到中序遍历时会得到的直接前驱
s = s->rchild;
s->rchild = p->rchild; //将p的右子树接为s的右子树
q = p;
p = p->lchild; //将p的左子树直接接到其父节点的左子树上
free(q);
}
}

void delete_Node2(BSTree &p)
{
BSTree q,s;
if(!p->lchild) //由于这个if在前面,所以左右子树均为空的情况会在这里处理
{ //如果左子树为空,则只需重接其右子树
q = p;
p = p->rchild ;
free(q);
}
else if(!p->rchild)
{ //如果右子树为空,则只需重接其左子树
q = p;
p = p->lchild;
free(q);
}
else
{ //如果左右子树都不为空,采取修改左子树的方法,也可以修改右子树,方法类似
q = p;
s = p->lchild; //取待删节点的左节点
while(s->rchild)
{ //找到中序遍历时会得到的直接前驱
q = s;
s = s->rchild;
}
//用s来替换待删节点p
p->data = s->data;
//根据情况,将s的左子树重接到q上
if(p != q)
q->rchild = s->lchild;
else
q->lchild =s->lchild;
free(s);
}
}

bool delete_BSTree(BSTree &T,int key)
{
//不存在关键字为key的节点
if(!T)
return false;
else
{
if(SearchBST(T,key)) //查找到关键字为key的节点
{
//delete_Node1(T);
delete_Node2(T);
return true;
}
else
{
cout<<"查无此值~"<<endl;
return false;
}
}
}

void CreateBST(BSTree &T) {

T=NULL;
ElemType e;
cout << "请输入值:0结束"<<endl;
cin >> e.key;

while (e.key!=0) {
InsertBST(T,e);
cout << "请继续输入"<<endl;
cin>>e.key;
}
}

void destroy_BSTree(BSTree pTree) //递归销毁二叉排序树
{
if(pTree)
{
if(pTree->lchild)
destroy_BSTree(pTree->lchild);
if(pTree->rchild)
destroy_BSTree(pTree->rchild);
free(pTree);
pTree = NULL;
}
}

static BSTree SingleRotateWithLeft(BSTree pNode) //LL型
{
BSTNode *pNode1;

pNode1 = pNode->lchild;
pNode->lchild = pNode1->rchild;
pNode1->rchild = pNode;

/*结点的位置变了, 要更新结点的高度值*/
pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
pNode1->nHeight = Max(Height(pNode1->lchild), pNode->nHeight) + 1;

return pNode1;
}

static BSTree SingleRotateWithRight(BSTree pNode) //RR型
{
BSTNode *pNode1;

pNode1 = pNode->rchild;
pNode->rchild = pNode1->lchild;
pNode1->lchild = pNode;

/*结点的位置变了, 要更新结点的高度值*/
pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
pNode1->nHeight = Max(Height(pNode1->rchild), pNode->nHeight) + 1;

return pNode1;
}

static BSTree DoubleRotateWithLeft(BSTree pNode) //LR型
{
pNode->lchild = SingleRotateWithRight(pNode->lchild);

return SingleRotateWithLeft(pNode);
}

static BSTree DoubleRotateWithRight(BSTree pNode)
{
pNode->rchild = SingleRotateWithLeft(pNode->rchild); //RL型

return SingleRotateWithRight(pNode);
}

//int main(){
// BSTree T;
// CreateBST(T);
// cout<<"删除前"<<endl;
// cout<<"先序遍历:";
// PreOrder(T);
// cout<<endl<<"中序遍历:";
// InOrder(T);
// cout<<"请输入删除的关键字"<<endl;
// int i;
// cin>>i;
// while (i!=0) {
// delete_BSTree(T,i);
// InOrder(T);
// cout << "请继续输入"<<endl;
// cin>>i;
// }
// cout<<"删除后"<<endl;
// InOrder(T);
// return 0;
//}

int main()
{
int i;
ElemType e;
BSTree T = NULL;

srand((unsigned int)time(NULL));

for (i = 0; i < 10; ++i)
{
e.key = rand()%100+1;
printf("%d\n", e.key);
InsertBST(T,e);
}

cout<<"先序遍历:";
PreOrder(T);
cout<<endl<<"中序遍历:";
InOrder(T);

destroy_BSTree(T);

return 0;
}

运行结果:

随机产生10个数字构建平衡二叉树,重复的产生值当然是插不进去的。
在这里插入图片描述
由运行结果的先序遍历和中序遍历可推导出这颗二叉树为:
在这里插入图片描述
可知构建的二叉树是平衡二叉树。

返回顶部

------------- Thank you for reading -------------

Title - Artist
0:00