您的位置:首页 > 理论基础 > 数据结构算法

数据结构——平衡二叉树

2018-02-06 15:24 295 查看

一、平衡二叉树的定义

  平衡二叉树(AVL 树)仍然是一棵二叉查找树,只是在其基础上增加了“平衡”的要求。所谓平衡是指,对 AVL 树的任意结点来说,其左子树与右子树的高度之差的绝对值不超过 1,其中左子树与右子树的高度之差称为该结点的平衡因子

  由于需要对每个结点都得到平衡因子,因此需要在树的结构中加入一个变量 height,用来记录以当前结点为根结点的子树的高度:

1 // 平衡二叉树结构体
2 struct node {
3     int v, height;            // v 为结点权值, height 为当前子树高度
4     node *lchild, *rchild;    // 左右孩子结点地址
5 };

 

 

  在这种定义下,如果需要新建一个结点,就可以采用如下写法:

1 // 平衡二叉树新建结点
2 node* newNode(int v) {
3     node* Node = (node*)malloc(sizeof(node));    // 申请地址空间
4     Node->v = v;                                // 结点权值为 v
5     Node->height = 1;                            // 结点高度初始为 1
6     Node->lchild = Node->rchild = NULL;            // 初始状态下没有左右孩子
7     return Node;
8 }

 

 

  可通过下面的函数获取结点 root 所在子树的当前高度:

// 获取以 root 为根结点的子树的当前高度
int getHeight(node* root) {
if(root == NULL)    return 0;    // 空树高度为 0
return root->height;
}

 

 

  于是根据定义,可以通过下面的函数计算平衡因子:

// 计算结点 root 的平衡因子
int getBalanceFactor(node* root) {
// 左子树高度减右子树高度
return getHeight(root->lchild) - getHeight(root->rchild);
}

 

 

  显然,结点 root 所在子树的 height 等于其左子树的 height 与右子树的 height 的较大值加 1,因此可通过下面的函数来更新 height:

1 // 更新结点 root 的高度
2 void updateHeight(node* root) {
3     // 根结点高度为左右子树高度较大值 +1
4     int lHeight = getHeight(root->lchild), rHeight = getHeight(root->rchild);
5     int max = lHeight > rHeight ? lHeight : rHeight;
6     root->height = max + 1;
7 }

 

 

 

二、平衡二叉树的基本操作

  和二叉查找树相同,AVL 树的基本操作有查找、插入、建树以及删除,由于删除操作较为复杂,因此主要介绍 AVL 树的查找、插入和建立。

  1. 查找操作

  由于 AVL 树是一棵二叉查找树,因此其查找操作的做法与二叉查找树相同。代码如下:

1 // 查找平衡二叉树中数据域为 x 的结点
2 void search(node* root, int x) {
3     if(root == NULL) {    // 空树,查找失败
4         printf("search failed\n");
5         return;
6     }
7     if(x == root->v) {    // 查找成功,访问之
8         printf("search success %d\n", root->v);
9     } else if(x < root->v) {        // x 比根结点的数据域小,往左子树查找
10         search(root->lchild, x);
11     } else {
12         search(root->rchild, x);    // x 比根结点的数据域大,往右子树查找
13     }
14 }

 

 

  2. 插入操作

  先来看一下几个插入问题需要用到的几个操作。

  左旋,调整步骤如下:

  1. [li] 让 B 的左子树 ♦ 成为 A 的右子树。
  2.  让 A 成为 B 的左子树
  3.  将根结点设定为结点 B    
[/li]

  

1 /*
2     平衡二叉树
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <math.h>
8 #include <stdlib.h>
9 #include <time.h>
10 #include <stdbool.h>
11
12 // 平衡二叉树结构体
13 typedef struct _node {
14     int v, height;            // v 为结点权值, height 为当前子树高度
15     struct _node *lchild, *rchild;    // 左右孩子结点地址
16 } node;
17
18 // 平衡二叉树新建结点
19 node* newNode(int v) {
20     node* Node = (node*)malloc(sizeof(node));    // 申请地址空间
21     Node->v = v;                                // 结点权值为 v
22     Node->height = 1;                            // 结点高度初始为 1
23     Node->lchild = Node->rchild = NULL;            // 初始状态下没有左右孩子
24     return Node;
25 }
26
27 // 获取以 root 为根结点的子树的当前高度
28 int getHeight(node* root) {
29     if(root == NULL)    return 0;    // 空树高度为 0
30     return root->height;
31 }
32
33 // 计算结点 root 的平衡因子
34 int getBalanceFactor(node* root) {
35     // 左子树高度减右子树高度
36     return getHeight(root->lchild) - getHeight(root->rchild);
37 }
38
39 // 更新结点 root 的高度
40 void updateHeight(node* root) {
41     // 根结点高度为左右子树高度较大值 +1
42     int lHeight = getHeight(root->lchild), rHeight = getHeight(root->rchild);
43     int max = lHeight > rHeight ? lHeight : rHeight;
44     root->height = max + 1;
45 }
46
47 // 查找平衡二叉树中数据域为 x 的结点
48 void search(node* root, int x) {
49     if(root == NULL) {    // 空树,查找失败
50         printf("search failed\n");
51         return;
52     }
53     if(x == root->v) {    // 查找成功,访问之
54         printf("search success %d\n", root->v);
55     } else if(x < root->v) {        // x 比根结点的数据域小,往左子树查找
56         search(root->lchild, x);
57     } else {
58         search(root->rchild, x);    // x 比根结点的数据域大,往右子树查找
59     }
60 }
61
62 // 左旋
63 void L(node** root) {
64     node* temp = (*root)->rchild;    // root指向A,temp指向B
65     (*root)->rchild = temp->lchild;    // 步骤 1
66     temp->lchild = *root;            // 步骤 2
67     updateHeight(*root);                // 更新高度
68     updateHeight(temp);
69     (*root) = temp;                    // 步骤 3
70 }
71
72 // 右旋
73 void R(node** root) {
74     node* temp = (*root)->lchild;    // root指向A,temp指向B
75     (*root)->lchild = temp->rchild;    // 步骤 1
76     temp->rchild = *root;            // 步骤 2
77     updateHeight(*root);                // 更新高度
78     updateHeight(temp);
79     (*root) = temp;                    // 步骤 3
80 }
81
82 // 插入权值为 v 的结点
83 void insert(node** root, int v) {
84     if((*root) == NULL) {        // 到达插入位置
85         (*root) = newNode(v);
86         return;
87     }
88     if(v < (*root)->v) {        // v 比根结点权值小
89         insert(&(*root)->lchild, v);        // 往左子树插入
90         updateHeight(*root);                // 更新树高
91         if(getBalanceFactor(*root) == 2) {
92             if(getBalanceFactor((*root)->lchild) == 1) {    // LL 型
93                 R(*root);
94             } else if(getBalanceFactor((*root)->lchild) == -1) {    // LR 型
95                 L(&(*root)->lchild);
96                 R(root);
97             }
98         }
99     } else {                    // v 比根结点权值大
100         insert(&(*root)->rchild, v);        // 往右子树插入
101         updateHeight(*root);                // 更新树高
102         if(getBalanceFactor(*root) == -2) {
103             if(getBalanceFactor((*root)->rchild) == -1) {    // RR 型
104                 L(root);
105             } else if(getBalanceFactor((*root)->rchild) == 1) {    // RL 型
106                 R(&(*root)->rchild);
107                 L(root);
108             }
109         }
110     }
111 }
112
113 // AVL 树的建立
114 node* create(int data[], int n) {
115     node* root = NULL;        // 新建根结点 root
116     int i;
117     for(i=0; i<n; ++i) {
118         insert(&root, data[i]);        // 将 data 中数据依次插入AVL树
119     }
120     return root;            // 返回根结点
121 }
122
123 // 先序遍历
124 void preorder(node* root) {
125     if(root == NULL) {
126         return;        // 空树,递归边界
127     }
128     printf("%d\n", root->v);        // 访问该结点
129     preorder(root->lchild);            // 访问左子树
130     preorder(root->rchild);            // 访问右子树
131 }
132
133 int main() {
134     int data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
135     node* root = NULL;
136     root = create(data, 10);    // 创建 AVL 树
137     preorder(root);                // 先序遍历
138     search(root, 10);            // 在 root 中查找 10
139     return 0;
140 }
平衡二叉树  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: