平衡二叉树(AVL)的实现,附可运行C语言代码

最近几月一直在自学C语言和数据结构,先是写了排序二叉树,觉得平衡二叉树作为一个经典数据结构,有必要实现一下。

网上看了些资料,在AVL和红黑树之间考虑,最后个人还是倾向于AVL。

不同于标准AVL的是,笔者没有使用平衡因子,直接根据左右孩子的高度差值判断是否平衡。整个平衡二叉树是在普通二叉查找树的基础上修改得到的,对于学习数据结构的同学来说,这样逐步提高难度,写起来挑战性没那么大。

代码经测试是可以运行,并实现插入、删除、修改节点时都可以保持平衡。相对于普通二叉查找树,AVL在查找时效率高耗时短,但为了保持高度平衡,必须牺牲插入和删除操作的复杂度。本文将分步讲解如何编写平衡二叉树,全文最后附有完整代码。

当左右子树的高度差超过1时(即≥2,在实际处理时,等于2即为不平衡,进行调整操作,所以不会出现大于2的情况),整棵树失去平衡。写代码之前先了解AVL是如何使二叉树保持平衡,这里涉及到对节点的旋转操作,分四种情况,左左,右右,左右,右左。下面分别解释:

一、左左单旋转

在节点x的左孩子插入节点b

①x无右孩子,旋转节点a即可达到平衡

②x有右孩子c,旋转节点a后,根据a>c>x,需将节点c移动到a的左子树

函数代码如下:

 1 static BTNode *singleRotateLL(BTree *BT, BTNode *phead)
 2 {//不平衡情况为左左的单旋转操作
 3     BTNode *temp;
 4
 5     if(phead == NULL)
 6         return 0;
 7
 8     temp = phead->lchild;
 9
10     if(temp->rchild != NULL){
11         phead->lchild = temp->rchild;
12         phead->lchild->height = tree_node_height(BT, phead->lchild);
13     }
14     else
15         phead->lchild = NULL;
16
17     temp->rchild = phead;
18     if(temp->rchild->data == BT->phead->data){
19         BT->phead = temp;
20     }
21     phead = temp;
22     temp->rchild->height = tree_node_height(BT, temp->rchild);
23     temp->height = tree_node_height(BT, temp);
24     phead->height = tree_node_height(BT, phead);
25
26     return phead;
27 }

二、右右单旋转

在节点x的右孩子插入节点b

①x无左孩子,旋转节点a即可达到平衡

②x有左孩子c,旋转节点a后,根据x>c>a,需将节点c移动到a的右子树

函数代码如下:

 1 static BTNode *singleRotateRR(BTree *BT, BTNode *phead)
 2 {//不平衡情况为右右的单旋转操作
 3     BTNode *temp;
 4
 5     if(phead == NULL)
 6         return 0;
 7
 8     temp = phead->rchild;
 9
10     if(temp->lchild != NULL){
11         phead->rchild = temp->lchild;
12         phead->rchild->height = tree_node_height(BT, phead->rchild);
13     }
14     else
15         phead->rchild = NULL;
16
17     temp->lchild = phead;
18     if(temp->lchild->data == BT->phead->data){
19         BT->phead = temp;
20     }
21     phead = temp;
22     temp->lchild->height = tree_node_height(BT, temp->lchild);
23     temp->height = tree_node_height(BT, temp);
24     phead->height = tree_node_height(BT, phead);
25
26     return phead;
27 }

注:需要注意的是节点旋转后,节点赋值和高度的更新,初学者很容易忽略或是弄错赋值顺序

三、左右双旋转

在节点x的右孩子插入节点b

①x无左孩子,②x有左孩子c,这两种情况的处理相同,首先对x节点进行右右单旋转操作,然后对a节点进行左左单旋转操作

函数代码如下:

 1 static BTNode *doubleRotateLR(BTree *BT, BTNode *phead)
 2 {//不平衡情况为左右的双旋转操作
 3     BTNode *temp;
 4
 5     if(phead == NULL)
 6         return 0;
 7
 8     temp = phead->lchild;
 9     phead->lchild = singleRotateRR(BT, temp);
10     temp = phead;
11     phead = singleRotateLL(BT, temp);
12
13     return phead;
14 }

四、右左双旋转

在节点x的右孩子插入节点b

①x无右孩子,②x有右孩子c,这两种情况的处理相同,首先对x节点进行左左单旋转操作,然后对a节点进行右右单旋转操作

函数代码如下:

 1 static BTNode *doubleRotateRL(BTree *BT, BTNode *phead)
 2 {//不平衡情况为右左的双旋转操作
 3     BTNode *temp;
 4
 5     if(phead == NULL)
 6         return 0;
 7
 8     temp = phead->rchild;
 9     phead->rchild = singleRotateLL(BT, temp);
10     temp = phead;
11     phead = singleRotateRR(BT, temp);
12
13     return phead;
14 }

弄清楚了怎样通过旋转达到平衡状态,接下来一步一步构造平衡二叉树。

第一步,我们要在二叉树的节点中加一个属性:高度,在后面的插入和删除函数中将会用到。

结构体代码如下:

1 typedef struct _BTNode{
2     TYPE data;
3     int height;
4     struct _BTNode *lchild;
5     struct _BTNode *rchild;
6 }BTNode;

第二步,需要添加三个辅助函数,一是求节点的高度,而是遍历求树中每个节点的高度(在删除函数中会用到),三是求两个高度的最大值。

 1 static int tree_node_height(BTree *BT, BTNode *phead)
 2 {//求节点的高度,写成函数解决指针为空的情况,默认空节点的高度为-1,只有一个根节点的节点的高度为0,每多一层高度加1
 3     if(phead != NULL){
 4         if(phead->lchild == NULL && phead->rchild == NULL){
 5             return 0;
 6         }
 7         else{
 8             return phead->height = max_height(tree_node_height(BT, phead->lchild), tree_node_height(BT, phead->rchild)) + 1;
 9         }
10     }
11     else{
12         return -1;
13     }
14 }
15
16 static void tree_height(BTree *BT, BTNode *phead)
17 {//遍历求树中每个节点的高度
18     if(phead == NULL)
19         return;
20
21     tree_node_height(BT, phead);
22     if(phead->lchild != NULL)
23         tree_node_height(BT, phead->lchild);
24     if(phead->rchild != NULL)
25         tree_node_height(BT, phead->rchild);
26 }
27
28 static int max_height(int height1, int height2)
29 {//求两个高度的最大值
30     if(height1 > height2)
31         return height1;
32     else
33         return height2;
34 }

第三步,插入

插入操作与二叉查找树的操作基本相同,只是在插入后需判断是否平衡,如果不平衡,进行旋转调整。因为BTNode没有使用父节点属性,所以需要用变量存储插入位置,以便调整后可以接回到二叉树上。树顶的根节点需特殊处理

 1 static BOOL tree_add(BTree *BT, BTNode *phead, TYPE value)
 2 {//按序插入结点
 3     if(phead == NULL)
 4         return 0;
 5
 6     if(phead->data == value)
 7         return 0;
 8
 9     else{
10         if(phead->data > value){
11             if(phead->lchild == NULL){
12                 BTNode *newnode = (BTNode*)calloc(1, sizeof(BTNode));
13                 newnode->data = value;
14                 newnode->lchild = newnode->rchild = NULL;
15                 phead->lchild = newnode;
16             }
17             else{
18                 tree_add(BT, phead->lchild, value);
19
20                 //判断插入节点后是否平衡,并调整
21                 BTNode *root;
22                 if(phead = BT->phead)
23                     root = phead;
24                 else
25                     root = phead->lchild;
26
27                 if(tree_node_height(BT, root->lchild) - tree_node_height(BT, root->rchild) == 2){
28                     if(root->lchild->data > value){
29                         root = singleRotateLL(BT, root);
30                     }
31                     else{
32                         root = doubleRotateLR(BT, root);
33                     }
34                 }
35                 phead = root;
36             }
37         }
38         else{
39             if(phead->rchild == NULL){
40                 BTNode *newnode = (BTNode*)calloc(1, sizeof(BTNode));
41                 newnode->data = value;
42                 newnode->lchild = newnode->rchild = NULL;
43                 phead->rchild = newnode;
44             }
45             else{
46                 tree_add(BT, phead->rchild, value);
47
48                 //判断插入节点后是否平衡,并调整
49                 BTNode *root;
50                 if(phead = BT->phead)
51                     root = phead;
52                 else
53                     root = phead->rchild;
54
55                 if(tree_node_height(BT, root->rchild) - tree_node_height(BT, root->lchild) == 2){
56                     if(root->rchild->data < value){
57                         root = singleRotateRR(BT, root);
58                     }
59                     else{
60                         root = doubleRotateRL(BT, root);
61                     }
62                 }
63                 phead = root;
64             }
65         }
66             phead->height = tree_node_height(BT, phead);
67             return 1;
68     }
69
70     return 0;
71 }

第四步,删除

平衡二叉树的删除操作比插入更复杂,因为删除后会引起一系列节点高度的改变,删除后将剩余子树接回二叉树时,要分三种情况处理,被删除节点是:顶部根节点、底部叶子(无子树)、普通节点。

 1 static BOOL tree_del(BTree *BT, BTNode **phead, TYPE value)
 2 {//删除结点
 3     BTNode *temp;
 4     BTNode *root;
 5     int flag;        //flag标记被删除的节点,默认顶部节点flag为0,左边节点flag为-1,右边节点flag为1
 6
 7     if(*phead == NULL)
 8         return 0;
 9
10     if(*phead == BT->phead){
11         flag = 0;
12         root = *phead;
13     }
14
15     else if((*phead)->lchild != NULL){
16         flag = -1;
17         root = (*phead)->lchild;
18     }
19
20     else if((*phead)->rchild != NULL){
21         flag = 1;
22         root = (*phead)->rchild;
23     }
24     else if((*phead)->lchild == NULL && (*phead)->rchild == NULL)
25         root = *phead;
26
27     if(root->data == value){
28         if(root->lchild != NULL){
29             temp = BT->search_max(BT, &root->lchild, 1);
30             temp->lchild = root->lchild;
31              temp->rchild = root->rchild;
32             free(root);
33             root = temp;
34             if(flag == 0)
35                 BT->phead = root;
36             else
37                 (*phead)->lchild = root;
38         }
39         else if(root->rchild != NULL){
40             temp = BT->search_min(BT, &root->rchild, 1);
41             temp->lchild = root->lchild;
42             temp->rchild = root->rchild;
43             free(root);
44             root = temp;
45             if(flag == 0)
46                 BT->phead = root;
47             else
48                 (*phead)->rchild = root;
49         }
50         else{
51             if(flag == 0)
52                 free(*phead);
53             else if(flag = -1){
54                 free((*phead)->lchild);
55                 (*phead)->lchild = NULL;
56             }
57             else if(flag = 1){
58                 free((*phead)->rchild);
59                 (*phead)->rchild = NULL;
60             }
61         }
62
63         tree_height(BT, BT->phead);    //删除节点后,求每个节点的新高度
64
65         if(flag == 0)
66             return 1;
67         if(flag == -1){
68             if(tree_node_height(BT, (*phead)->rchild) - tree_node_height(BT, (*phead)->lchild) == 2){
69                 if((*phead)->rchild->rchild != NULL){
70                     root = singleRotateRR(BT, *phead);
71                 }
72                 else{
73                     root = doubleRotateRL(BT, *phead);
74                 }
75             }
76         }
77         else{
78             if(tree_node_height(BT, (*phead)->lchild) - tree_node_height(BT, (*phead)->rchild) == 2){
79                 if((*phead)->lchild->lchild != NULL){
80                     root = singleRotateLL(BT, *phead);
81                 }
82                 else{
83                     root = doubleRotateLR(BT, *phead);
84                 }
85             }
86         }
87
88         return 1;
89     }
90     else if(root->data > value)
91         return BT->del(BT, &root->lchild, value);
92     else
93         return BT->del(BT, &root->rchild, value);
94
95     return 0;
96 }

除了插入和删除操作,其他操作均与普通二叉查找树一样。

如果读者发现错误或有更好的处理方法,请指出,以便修改完善。

头文件binary.h代码:

 1 #ifndef BINARY_H
 2 #define BINARY_H
 3
 4 typedef int TYPE;
 5 typedef int BOOL;
 6
 7 typedef struct _BTNode{
 8     TYPE data;
 9     int height;
10     struct _BTNode *lchild;
11     struct _BTNode *rchild;
12 }BTNode;
13
14 typedef struct _BTree{
15     BTNode *phead;
16
17     void(*init)(struct _BTree *BT, TYPE head_value);
18     void(*exit)(struct _BTree *BT);
19     void(*print)(struct _BTree *BT, BTNode *phead);
20
21     BOOL(*add)(struct _BTree *BT, BTNode *phead, TYPE value);
22     BOOL(*del)(struct _BTree *BT, BTNode **phead, TYPE value);
23     BOOL(*del_tree)(struct _BTree *BT, BTNode **phead);
24     BOOL(*alter)(struct _BTree *BT, BTNode *phead, TYPE value, TYPE new_value);
25     BTNode *(*search)(struct _BTree *BT, BTNode *phead, TYPE value);
26
27     BTNode *(*search_min)(struct _BTree *BT, BTNode **phead, int flag);
28     BTNode *(*search_max)(struct _BTree *BT, BTNode **phead, int flag);
29
30     void(*pre_traverse)(struct _BTree *BT, BTNode *phead);
31     void(*mid_traverse)(struct _BTree *BT, BTNode *phead);
32     void(*last_traverse)(struct _BTree *BT, BTNode *phead);
33
34     //以下为实现AVL所需函数
35     int (*node_height)(_BTree *BT, BTNode *phead);
36     void (*height)(_BTree *BT, BTNode *phead);
37     int (*max_height)(int height1, int height2);
38     BTNode *(*singleRotateLL)(_BTree *BT, BTNode *phead);
39     BTNode *(*singleRotateRR)(_BTree *BT, BTNode *phead);
40     BTNode *(*doubleRotateLR)(_BTree *BT, BTNode *phead);
41     BTNode *(*doubleRotateRL)(_BTree *BT, BTNode *phead);
42 }BTree;
43
44 void tree_init(BTree *BT, TYPE value);
45 void tree_exit(BTree *BT);
46
47 #endif

源文件binary.cpp代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4
  5 #include "binary.h"
  6
  7 void tree_init(BTree *BT, TYPE head_value);
  8 void tree_exit(BTree *BT);
  9 void tree_print(BTree *BT, BTNode *phead);
 10 static BOOL tree_add(BTree *BT, BTNode *phead, TYPE value);
 11 static BOOL tree_del(BTree *BT, BTNode **phead, TYPE value);
 12 static BOOL tree_del_tree(BTree *BT, BTNode **phead);
 13 static BOOL tree_alter(BTree *BT, BTNode *phead, TYPE value, TYPE new_value);
 14 static BTNode *tree_search(BTree *BT, BTNode *phead, TYPE value);
 15 static BTNode *tree_search_min(BTree *BT, BTNode **phead, int flag);
 16 static BTNode *tree_search_max(BTree *BT, BTNode **phead, int flag);
 17 static void tree_pre_traverse(BTree *BT, BTNode *phead);
 18 static void tree_mid_traverse(BTree *BT, BTNode *phead);
 19 static void tree_last_traverse(BTree *BT, BTNode *phead);
 20
 21 //以下为实现AVL所需函数
 22 static int tree_node_height(BTree *BT, BTNode *phead);
 23 static void tree_height(BTree *BT, BTNode *phead);
 24 static int max_height(int height1, int height2);
 25 static BTNode *singleRotateLL(BTree *BT, BTNode *phead);
 26 static BTNode *singleRotateRR(BTree *BT, BTNode *phead);
 27 static BTNode *doubleRotateLR(BTree *BT, BTNode *phead);
 28 static BTNode *doubleRotateRL(BTree *BT, BTNode *phead);
 29
 30
 31 void tree_init(BTree *BT, TYPE head_value)
 32 {//初始化
 33     BT->phead = (BTNode*)calloc(1, sizeof(BTNode));
 34     BT->phead->data = head_value;
 35
 36     BT->phead->lchild = BT->phead->rchild = NULL;
 37
 38     BT->add = tree_add;
 39     BT->del = tree_del;
 40     BT->print = tree_print;
 41     BT->del_tree = tree_del_tree;
 42     BT->alter = tree_alter;
 43     BT->search = tree_search;
 44     BT->search_min = tree_search_min;
 45     BT->search_max = tree_search_max;
 46     BT->pre_traverse = tree_pre_traverse;
 47     BT->mid_traverse = tree_mid_traverse;
 48     BT->last_traverse = tree_last_traverse;
 49     BT->exit = tree_exit;
 50
 51     BT->node_height = tree_node_height;
 52     BT->height = tree_height;
 53     BT->max_height = max_height;
 54     BT->singleRotateLL = singleRotateLL;
 55     BT->singleRotateRR = singleRotateRR;
 56     BT->doubleRotateLR = doubleRotateLR;
 57     BT->doubleRotateRL = doubleRotateRL;
 58 }
 59
 60 void tree_exit(BTree *BT)
 61 {//结束操作
 62     if(BT != NULL)
 63         BT->del_tree(BT, &BT->phead);
 64 }
 65
 66 void tree_print(BTree *BT, BTNode *phead)
 67 {//打印结点
 68     if(phead != NULL)
 69         printf("%d\n", phead->data);
 70 }
 71
 72 static BOOL tree_add(BTree *BT, BTNode *phead, TYPE value)
 73 {//按序插入结点
 74     if(phead == NULL)
 75         return 0;
 76
 77     if(phead->data == value)
 78         return 0;
 79
 80     else{
 81         if(phead->data > value){
 82             if(phead->lchild == NULL){
 83                 BTNode *newnode = (BTNode*)calloc(1, sizeof(BTNode));
 84                 newnode->data = value;
 85                 newnode->lchild = newnode->rchild = NULL;
 86                 phead->lchild = newnode;
 87             }
 88             else{
 89                 tree_add(BT, phead->lchild, value);
 90
 91                 //判断插入节点后是否平衡,并调整
 92                 BTNode *root;
 93                 if(phead = BT->phead)
 94                     root = phead;
 95                 else
 96                     root = phead->lchild;
 97
 98                 if(tree_node_height(BT, root->lchild) - tree_node_height(BT, root->rchild) == 2){
 99                     if(root->lchild->data > value){
100                         root = singleRotateLL(BT, root);
101                     }
102                     else{
103                         root = doubleRotateLR(BT, root);
104                     }
105                 }
106                 phead = root;
107             }
108         }
109         else{
110             if(phead->rchild == NULL){
111                 BTNode *newnode = (BTNode*)calloc(1, sizeof(BTNode));
112                 newnode->data = value;
113                 newnode->lchild = newnode->rchild = NULL;
114                 phead->rchild = newnode;
115             }
116             else{
117                 tree_add(BT, phead->rchild, value);
118
119                 //判断插入节点后是否平衡,并调整
120                 BTNode *root;
121                 if(phead = BT->phead)
122                     root = phead;
123                 else
124                     root = phead->rchild;
125
126                 if(tree_node_height(BT, root->rchild) - tree_node_height(BT, root->lchild) == 2){
127                     if(root->rchild->data < value){
128                         root = singleRotateRR(BT, root);
129                     }
130                     else{
131                         root = doubleRotateRL(BT, root);
132                     }
133                 }
134                 phead = root;
135             }
136         }
137             phead->height = tree_node_height(BT, phead);
138             return 1;
139     }
140
141     return 0;
142 }
143
144 static BOOL tree_del(BTree *BT, BTNode **phead, TYPE value)
145 {//删除结点
146     BTNode *temp;
147     BTNode *root;
148     int flag;        //flag标记被删除的节点,默认顶部节点flag为0,左边节点flag为-1,右边节点flag为1
149
150     if(*phead == NULL)
151         return 0;
152
153     if(*phead == BT->phead){
154         flag = 0;
155         root = *phead;
156     }
157
158     else if((*phead)->lchild != NULL){
159         flag = -1;
160         root = (*phead)->lchild;
161     }
162
163     else if((*phead)->rchild != NULL){
164         flag = 1;
165         root = (*phead)->rchild;
166     }
167     else if((*phead)->lchild == NULL && (*phead)->rchild == NULL)
168         root = *phead;
169
170     if(root->data == value){
171         if(root->lchild != NULL){
172             temp = BT->search_max(BT, &root->lchild, 1);
173             temp->lchild = root->lchild;
174              temp->rchild = root->rchild;
175             free(root);
176             root = temp;
177             if(flag == 0)
178                 BT->phead = root;
179             else
180                 (*phead)->lchild = root;
181         }
182         else if(root->rchild != NULL){
183             temp = BT->search_min(BT, &root->rchild, 1);
184             temp->lchild = root->lchild;
185             temp->rchild = root->rchild;
186             free(root);
187             root = temp;
188             if(flag == 0)
189                 BT->phead = root;
190             else
191                 (*phead)->rchild = root;
192         }
193         else{
194             if(flag == 0)
195                 free(*phead);
196             else if(flag = -1){
197                 free((*phead)->lchild);
198                 (*phead)->lchild = NULL;
199             }
200             else if(flag = 1){
201                 free((*phead)->rchild);
202                 (*phead)->rchild = NULL;
203             }
204         }
205
206         tree_height(BT, BT->phead);    //删除节点后,求每个节点的新高度
207
208         if(flag == 0)
209             return 1;
210         if(flag == -1){
211             if(tree_node_height(BT, (*phead)->rchild) - tree_node_height(BT, (*phead)->lchild) == 2){
212                 if((*phead)->rchild->rchild != NULL){
213                     root = singleRotateRR(BT, *phead);
214                 }
215                 else{
216                     root = doubleRotateRL(BT, *phead);
217                 }
218             }
219         }
220         else{
221             if(tree_node_height(BT, (*phead)->lchild) - tree_node_height(BT, (*phead)->rchild) == 2){
222                 if((*phead)->lchild->lchild != NULL){
223                     root = singleRotateLL(BT, *phead);
224                 }
225                 else{
226                     root = doubleRotateLR(BT, *phead);
227                 }
228             }
229         }
230
231         return 1;
232     }
233     else if(root->data > value)
234         return BT->del(BT, &root->lchild, value);
235     else
236         return BT->del(BT, &root->rchild, value);
237
238     return 0;
239 }
240
241 static BOOL tree_del_tree(BTree *BT, BTNode **phead)
242 {//删除二叉树
243     if(*phead == NULL)
244         return 0;
245
246     if((*phead)->lchild != NULL)
247         BT->del_tree(BT, &(*phead)->lchild);
248     if((*phead)->rchild != NULL)
249         BT->del_tree(BT, &(*phead)->rchild);
250
251     free(*phead);
252     *phead = NULL;
253
254     return 1;
255 }
256
257 static BOOL tree_alter(BTree *BT, BTNode *phead, TYPE value, TYPE new_value)
258 {//更改结点的值(先删除,后插入)
259     if(phead == NULL)
260         return 0;
261
262     if(value == new_value)
263         return 1;
264
265     if(BT->del(BT, &phead, value) != 0){
266         if(BT->add(BT, phead, new_value) != 0)
267             return 1;
268         else
269             return 0;
270     }
271     else
272         return 0;
273 }
274
275 static BTNode *tree_search(BTree *BT, BTNode *phead, TYPE value)
276 {//查找结点
277     BTNode *temp;
278
279     if(phead == NULL)
280         return NULL;
281
282     if(phead->data == value)
283         return phead;
284     if(phead->lchild != NULL){
285         temp = BT->search(BT, phead->lchild, value);
286         if(temp != NULL)
287             return temp;
288     }
289     if(phead->rchild != NULL){
290         temp = BT->search(BT, phead->rchild, value);
291         if(temp != NULL)
292             return temp;
293     }
294
295     return NULL;
296 }
297
298 static BTNode *tree_search_min(BTree *BT, BTNode **phead, int flag)
299 {//查找最小结点
300     BTNode *temp;
301
302     if(*phead == NULL)
303         return NULL;
304
305     if((*phead)->lchild == NULL){
306         temp = *phead;
307         if(flag == 1)
308             *phead = (*phead)->rchild;
309         return temp;
310     }
311     else
312         return BT->search_min(BT, &(*phead)->lchild, flag);
313 }
314
315 static BTNode *tree_search_max(BTree *BT, BTNode **phead, int flag)
316 {//查找最大结点
317     BTNode *temp;
318
319     if(*phead == NULL)
320         return NULL;
321
322     if((*phead)->rchild == NULL){
323         temp = *phead;
324         if(flag == 1)
325             *phead = (*phead)->lchild;
326         return temp;
327     }
328     else
329         return BT->search_max(BT, &(*phead)->rchild, flag);
330 }
331
332 static void tree_pre_traverse(BTree *BT, BTNode *phead)
333 {//先序遍历二叉树
334     if(phead == NULL)
335         return;
336
337     BT->print(BT, phead);
338     if(phead->lchild != NULL)
339         BT->pre_traverse(BT, phead->lchild);
340     if(phead->rchild != NULL)
341         BT->pre_traverse(BT, phead->rchild);
342 }
343
344 static void tree_mid_traverse(BTree *BT, BTNode *phead)
345 {//中序遍历二叉树
346     if(phead == NULL)
347         return;
348
349     if(phead->lchild != NULL)
350         BT->mid_traverse(BT, phead->lchild);
351     BT->print(BT, phead);
352     if(phead->rchild != NULL)
353         BT->mid_traverse(BT, phead->rchild);
354 }
355
356 static void tree_last_traverse(BTree *BT, BTNode *phead)
357 {//后序遍历二叉树
358     if(phead == NULL)
359         return;
360
361     if(phead->lchild != NULL)
362         BT->last_traverse(BT, phead->lchild);
363     if(phead->rchild != NULL)
364         BT->last_traverse(BT, phead->rchild);
365     BT->print(BT, phead);
366 }
367
368 static int tree_node_height(BTree *BT, BTNode *phead)
369 {//求节点的高度,写成函数解决指针为空的情况,默认空节点的高度为-1,只有一个根节点的节点的高度为0,每多一层高度加1
370     if(phead != NULL){
371         if(phead->lchild == NULL && phead->rchild == NULL){
372             return 0;
373         }
374         else{
375             return phead->height = max_height(tree_node_height(BT, phead->lchild), tree_node_height(BT, phead->rchild)) + 1;
376         }
377     }
378     else{
379         return -1;
380     }
381 }
382
383 static void tree_height(BTree *BT, BTNode *phead)
384 {//遍历求树中每个节点的高度
385     if(phead == NULL)
386         return;
387
388     tree_node_height(BT, phead);
389     if(phead->lchild != NULL)
390         tree_node_height(BT, phead->lchild);
391     if(phead->rchild != NULL)
392         tree_node_height(BT, phead->rchild);
393 }
394
395 static int max_height(int height1, int height2)
396 {//求两个高度的最大值
397     if(height1 > height2)
398         return height1;
399     else
400         return height2;
401 }
402
403 static BTNode *singleRotateLL(BTree *BT, BTNode *phead)
404 {//不平衡情况为左左的单旋转操作
405     BTNode *temp;
406
407     if(phead == NULL)
408         return 0;
409
410     temp = phead->lchild;
411
412     if(temp->rchild != NULL){
413         phead->lchild = temp->rchild;
414         phead->lchild->height = tree_node_height(BT, phead->lchild);
415     }
416     else
417         phead->lchild = NULL;
418
419     temp->rchild = phead;
420     if(temp->rchild->data == BT->phead->data){
421         BT->phead = temp;
422     }
423     phead = temp;
424     temp->rchild->height = tree_node_height(BT, temp->rchild);
425     temp->height = tree_node_height(BT, temp);
426     phead->height = tree_node_height(BT, phead);
427
428     return phead;
429 }
430
431 static BTNode *singleRotateRR(BTree *BT, BTNode *phead)
432 {//不平衡情况为右右的单旋转操作
433     BTNode *temp;
434
435     if(phead == NULL)
436         return 0;
437
438     temp = phead->rchild;
439
440     if(temp->lchild != NULL){
441         phead->rchild = temp->lchild;
442         phead->rchild->height = tree_node_height(BT, phead->rchild);
443     }
444     else
445         phead->rchild = NULL;
446
447     temp->lchild = phead;
448     if(temp->lchild->data == BT->phead->data){
449         BT->phead = temp;
450     }
451     phead = temp;
452     temp->lchild->height = tree_node_height(BT, temp->lchild);
453     temp->height = tree_node_height(BT, temp);
454     phead->height = tree_node_height(BT, phead);
455
456     return phead;
457 }
458 static BTNode *doubleRotateLR(BTree *BT, BTNode *phead)
459 {//不平衡情况为左右的双旋转操作
460     BTNode *temp;
461
462     if(phead == NULL)
463         return 0;
464
465     temp = phead->lchild;
466     phead->lchild = singleRotateRR(BT, temp);
467     temp = phead;
468     phead = singleRotateLL(BT, temp);
469
470     return phead;
471 }
472
473 static BTNode *doubleRotateRL(BTree *BT, BTNode *phead)
474 {//不平衡情况为右左的双旋转操作
475     BTNode *temp;
476
477     if(phead == NULL)
478         return 0;
479
480     temp = phead->rchild;
481     phead->rchild = singleRotateLL(BT, temp);
482     temp = phead;
483     phead = singleRotateRR(BT, temp);
484
485     return phead;
486 }
487
488 int main(int argc, char* argv[])
489 {//测试
490     BTree testtree;
491     testtree.init = tree_init;
492     testtree.init(&testtree, 9);
493
494     testtree.add(&testtree, testtree.phead, 4);
495     testtree.add(&testtree, testtree.phead, 5);
496     testtree.add(&testtree, testtree.phead, 6);
497     testtree.add(&testtree, testtree.phead, 1);
498     testtree.add(&testtree, testtree.phead, 7);
499     testtree.add(&testtree, testtree.phead, 8);
500     testtree.add(&testtree, testtree.phead, 11);
501     testtree.add(&testtree, testtree.phead, 10);
502
503     testtree.pre_traverse(&testtree, testtree.phead);
504     printf("\n");
505     testtree.mid_traverse(&testtree, testtree.phead);
506     printf("\n");
507     testtree.last_traverse(&testtree, testtree.phead);
508     printf("\n");
509
510     printf("%d\n", (testtree.search(&testtree, testtree.phead, 8))->data);
511     printf("\n");
512
513     testtree.del(&testtree, &testtree.phead, 4);
514     testtree.del(&testtree, &testtree.phead, 1);
515     testtree.del(&testtree, &testtree.phead, 6);
516     testtree.alter(&testtree, testtree.phead, 9, 2);
517
518     testtree.pre_traverse(&testtree, testtree.phead);
519     printf("\n");
520     testtree.mid_traverse(&testtree, testtree.phead);
521     printf("\n");
522     testtree.last_traverse(&testtree, testtree.phead);
523     printf("\n");
524
525     return 0;
526 }

时间: 2024-11-09 20:36:34

平衡二叉树(AVL)的实现,附可运行C语言代码的相关文章

图解平衡二叉树,AVL树(一)

图解平衡二叉树,AVL树(一) 学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建立的树如图2,才能够最大地体现二叉树的优点. 在上述的例子中,图2就是一棵平衡二叉树.科学家们提出平衡二叉树,就是为了让树的查找性能得到最大的体现(至少我是这样理解的,欢迎批评改正).下面进入今天的正题,平衡二叉树. AVL的定义 平衡二叉查找树:简称平衡二叉树.由前

平衡二叉树 AVL 的插入节点后旋转方法分析

平衡二叉树 AVL( 发明者为Adel'son-Vel'skii 和 Landis)是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1. 首先我们知道,当插入一个节点,从此插入点到树根节点路径上的所有节点的平衡都可能被打破,如何解决这个问题呢? 这里不讲大多数书上提的什么平衡因子,什么最小不平衡子树,实际上让人(me)更加费解.实际上你首要做的就是先找到第一个出现不平衡的节点,也就是高度最高的那个节点A,对以它为根的子树做一次旋转或者两次旋转,此时这个节点的平衡问题解决了,整个往

数据结构快速回顾——平衡二叉树 AVL (转)

平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树.1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树.平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态.这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(

单点登录SSO:可一键运行的完整代码

h1.title,h2.title { padding-left: 2rem !important; color: rgb(71, 91, 204) !important } h1.title { font-size: 22px !important } h2.title { font-size: 18px !important } .padding { padding: 0 2rem; padding-bottom: 1rem } blockquote.menu { padding-left:

如何让编辑器运行你的代码

如何让编辑器运行你的代码 Unity3D可以通过事件触发来执行你的编辑器代码,但是我们需要一些编译器参数来告知编译器何时需要触发该段代码. [MenuItem(XXX)]声明在一个函数上方,告知编译器给Unity3D编辑器添加一个菜单项,并且当点击该菜单项的时候调用该函数.触发函数里可以编写任何合法的代码,可以是一个资源批处理程序,也可以弹出一个编辑器窗口.代码里可以访问到当前选中的内容(通过Selection类),并据此来确定显示视图.与此类似,[ContextMenu("XXX")

Ubuntu 12.04下在Eclipse IDE for C/C++ Developers中运行C语言的GTK程序

哈哈哈--终于搞定了GTK程序的编译与运行,纠结了近一个月的问题终于得以解决,痛快!近一个月来,不断百度.发博文.百度知道提问.csdn提问--经常发私信.评论博文麻烦大牛,比如sunny2038.轻飘风扬.Sun1956--在此对所有帮助我的人表示感谢! 特别感谢csdn的sunny2038,他的博文<Windows和Ubuntu11.10在Eclipse中配置C和GTK>和热心回复给了我很大的帮助! Neo E. Cai的博文<Ubuntu下GTK的安装.编译和测试>对我具有非

unicode string和ansi string的转换函数及获取程序运行路径的代码

#pragma once#include <string> namespace stds { class tool { public: std::string ws2s(const std::wstring& ws) { std::string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C"; setlocale(LC_ALL, "chs"); const wchar_t* _Sou

Swift和OC,是编译型语言、解释性语言、运行时语言

首先需要明确的一点是,什么是编译型语言和解释性语言 编译型语言,就是在其执行过程中需要先将其经过编译成机器码来给计算机识别的,其执行效率就会比较高这个是显而易见的,常见比如:C.C++ 而解释型语言,是不用编译这个过程的,只是在执行时通过相应的翻译器(虚拟机)逐行翻译.这样它的跨平台性就会较好,因为可以直接通过编译器编译成需要的平台上的语言,但是有一个问题就是:它每次运行都要讲每行代码逐行解释翻译一遍.常见比如:Python.JS.PHP 由此可见,我们的OC和Swift都是需要先进行编译后才能

vs2013运行c语言出现:无法查找或打开 PDB 文件。

vs2013运行c语言出现:无法查找或打开 PDB 文件. “ConsoleApplication1.exe”(Win32): 已加载“C:\Users\hp\Documents\Visual Studio 2013\Projects\ConsoleApplication1\Debug\ConsoleApplication1.exe”.已加载符号. “ConsoleApplication1.exe”(Win32): 已加载“C:\Windows\SysWOW64\ntdll.dll”.无法查找或