数据结构——平衡二叉树
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. 插入操作
先来看一下几个插入问题需要用到的几个操作。
左旋,调整步骤如下:
- [li] 让 B 的左子树 ♦ 成为 A 的右子树。
- 让 A 成为 B 的左子树
- 将根结点设定为结点 B
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 }平衡二叉树
相关文章推荐
- 数据结构-平衡二叉树(AVL Tree)
- (模板题)sdut 3374 数据结构实验之查找二:平衡二叉树(平衡二叉树的建立)
- 数据结构—平衡二叉树
- 数据结构作业——魔法少女(平衡二叉树)
- 数据结构—平衡二叉树
- 3374 数据结构实验之查找二:平衡二叉树
- 数据结构实验之查找二:平衡二叉树
- 数据结构—平衡二叉树
- 数据结构实验之查找二:平衡二叉树
- 数据结构实验之查找二:平衡二叉树
- 数据结构作业——魔法少女(平衡二叉树)
- SDUT 3374 数据结构实验之查找二:平衡二叉树
- 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)
- sdutacm-数据结构实验之查找二:平衡二叉树
- 数据结构实验之查找二:平衡二叉树
- 数据结构实验之查找二:平衡二叉树
- 数据结构实验之查找二:平衡二叉树
- 数据结构——平衡二叉树(AVL树)
- 数据结构例程——平衡二叉树
- 数据结构实验之查找二:平衡二叉树