当前位置:   article > 正文

平衡二叉树算法实现C++_平衡二叉树c++

平衡二叉树c++

数据结构课程设计之平衡二叉树算法实现。

什么是平衡二叉树

是一种结构平衡的二叉搜索树,是一种每个节点的左右子树高度差都不超过1的二叉树。

由前苏联的数学家 Adelse-Velskil 和 Landis 在 1962 年提出的高度平衡的二叉树,根据科学家的英文名也称为 AVL 树。它具有如下几个性质:

  1. 可以是空树。
  2. 假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过 1。

举个例子,下图不是平衡二叉树,因为结点 60 的左子树高度为2,右子树高度为0,高度超过1。

什么是二叉搜索树?

它或者是一棵空树,或者是具有下列性质的 二叉树 : 若它的左子树不空,则左子树上所有结点的值均小于它的 根结点 的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为 二叉排序树 。. 二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。

为什么要拥有平衡二叉树呢?

二叉搜索树一定程度上可以提高搜索效率,但是当原序列有序时,例如序列 A = {1,2,3,4,5,6},构造二叉搜索树如下图。依据此序列构造的二叉搜索树为右斜树,同时二叉树退化成单链表,搜索效率降低为 O(n)。

二叉搜索树的查找效率取决于树的高度,因此保持树的高度最小,即可保证树的查找效率。同样的序列 A,将其改为下图的方式存储,查找元素 6 时只需比较 3 次,查找效率提升一倍。

可以看出当节点数目一定,保持树的左右两端保持平衡,树的查找效率最高。

这种左右子树的高度相差不超过 1 的树为平衡二叉树。

平衡因子:

某结点的左子树和右子树的高度差即为该结点的平衡因子,平衡二叉树中不存在平衡因子大于 1 的节点。

如何构造平衡二叉树?

首先我们知道,平衡二叉树是一颗二叉树,我们二叉树结构具有左子树、右子树、值,而在平衡二叉树,由于我们需要检查它的平衡性,以及失衡调整操作,我们需要定义一个深度。下面代码块是平衡二叉树的定义。

  1. //平衡二叉树的结构
  2. typedef struct AVLNode{
  3. int depth;//深度
  4. struct AVLNode *left;//左孩子
  5. struct AVLNode *right;//右孩子
  6. struct AVLNode *parent;//父结点
  7. ElenmentType value; //
  8. }AVLtree,Tree;

平衡二叉树的初始化:
 

  1. //初始化
  2. Tree* Init(ElenmentType value){
  3. Tree* root=new Tree();
  4. root->parent = NULL;
  5. root->depth = 0;
  6. root->left = root->right = NULL;
  7. root->value=value;
  8. return root;
  9. }

平衡二叉树插入时的失衡和调整

二叉树的基本操作有:插入、删除、遍历等。

对于平衡二叉树而言,插入和删除会导致二叉树的失衡。

下图是一棵平衡二叉树

在此平衡二叉树插入节点 99 ,树结构变为:

节点 66 的左子树高度为 1,右子树高度为 3,此时平衡因子为 -2,树失去平衡。

最小失衡子树:在新插入的结点向上查找,以第一个平衡因子的绝对值超过 1 的结点为根的子树称为最小不平衡子树。也就是说,一棵失衡的树,是有可能有多棵子树同时失衡的。而这个时候,我们只要调整最小的不平衡子树,就能够将不平衡的树调整为平衡的树。 

平衡二叉树的失衡调整主要是通过旋转最小失衡子树来实现的。

根据旋转的方向有两种处理方式,左旋 与 右旋 。

旋转的目的就是减少高度,通过降低整棵树的高度来平衡。哪边的树高,就把那边的树向上旋转。

左旋:

在下图中,加入新节点 99 后, 节点 66 的左子树高度为 1,右子树高度为 3,此时平衡因子为 -2。为保证树的平衡,此时需要对节点 66 做出旋转,因为右子树高度高于左子树,对节点进行左旋操作,流程如下:

(1)节点的右孩子替代此节点位置 (2)右孩子的左子树变为该节点的右子树 (3)节点本身变为右孩子的左子树

  • 节点的右孩子替代此节点位置 —— 节点 66 的右孩子是节点 77 ,将节点 77 代替节点 66 的位置
  • 右孩子的左子树变为该节点的右子树 —— 节点 77 的左子树为节点 75,将节点 75 挪到节点 66 的右子树位置
  • 节点本身变为右孩子的左子树 —— 节点 66 变为了节点 77 的左子树
  1. //RR型调整函数,执行左旋
  2. Tree* RR_rotate(Tree * root){
  3. Tree* temp;
  4. temp = root->right;
  5. root->right = temp->left;
  6. temp->left = root;
  7. return temp;
  8. }

右旋:

(1)节点的左孩子代表此节点 (2)节点的左孩子的右子树变为节点的左子树 (3)将此节点作为左孩子节点的右子树。

  1. //LL型调整函数,执行右旋
  2. Tree* LL_rotate(Tree *root){
  3. Tree *temp;
  4. temp = root->left;
  5. root->left = temp->right;
  6. temp->right = root;
  7. return temp;
  8. }

四种可能的插入方式:

 LL和RR的插入方式中,我们对最小失衡子树实现右旋和左旋即可。

若 A 的左孩子节点 B 的右子树 E 插入节点 F ,导致节点 A 失衡,如图

这种称为LR的插入方式,在LR的插入方式中,我们先对最小失衡子树A的左孩子B进行左旋,再对最小失衡子树A进行右旋.

  1. //LR型调整函数,先左旋转,再右旋转
  2. Tree* LR_rotate(Tree* root){
  3. Tree* temp;
  4. temp = root->left;
  5. root->left =RR_rotate(temp);
  6. return LL_rotate(root);
  7. }

若 A 的右孩子节点 C 的左子树 D 插入节点 F ,导致节点 A 失衡,如图 

这种称为RL的插入方式,在RL的插入方式中,我们先对最小失衡子树 A 的右孩子 C 进行右旋操作,再对最小失衡子树 A 做左旋操作。

  1. //RL型调整函数,先右旋转,再左旋转
  2. Tree* RL_rotate(Tree* root){
  3. Tree* temp;
  4. temp = root->right;
  5. root->right=LL_rotate(temp);
  6. return RR_rotate(root);
  7. }
  1. //插入结点
  2. Tree* Insert(Tree* root,ElenmentType k )
  3. {
  4. if (NULL == root)
  5. {
  6. root = Init(k);//如果根结点为null,则直接将值为根结点
  7. if(root==NULL)
  8. cout<<"创建失败"<<endl;
  9. return root;
  10. }
  11. else if (k < root->value)
  12. {
  13. root->left = Insert(root->left, k);//递归左子树
  14. root = Balance(root);//平衡操作
  15. }
  16. else if (k>root->value)
  17. {
  18. root->right = Insert(root->right, k);//递归右子树
  19. root = Balance(root);//平衡操作
  20. }
  21. return root;
  22. }

平衡二叉树删除时的失衡和调整

删除操作分为四种情况:
(1)删除叶子节点

(2)删除的节点只有左子树

(3)删除的节点只有右子树

(4)删除的节点既有左子树又有右子树 

AVL 树在删除节点后需要重新检查平衡性并修正,同时,删除操作与插入操作后的平衡修正区别在于,插入操作只需要调整最小的不平衡子树,而删除操作需要调整所有的不平衡子树。

删除操作的大致步骤如下:

1.查找删除元素是否存在

2.删除元素的值与根节点的值的比较,删除元素的值若小于根节点的值,则往左边删,大于则往右边删,直到找到删除节点。

3.判断删除的节点的情况,是既有左子树又有右子树,还是只有左子树,还是只有右子树,还是为叶子节点。

4.根据不同的情况进行删除

若删除的节点既有左子树又有右子树

     1)左子树更高,在左边删除,以左子树的最大值替换当前值,删除左子树中已经替换上去的节点。(删除替换节点进行了递归)

     2)右子树更高,在右边删除,以右子树的最小值替换当前值,删除右子树中已经替换上去的节点。(删除替换节点进行了递归)

若删除的节点只有一个孩子或者为叶子节点,那么我们可以直接进行删除。

5.删除之后,进行平衡性检查,若失衡,则进行失衡调整。

注:对于删除操作造成的非平衡状态的修正,可以这样理解:对左或者右子树的删除操作相当于对右或者左子树的插入操作,然后再对应上插入的四种情况选择相应的旋转就好了。

  1. //删除结点
  2. Tree* Delete(Tree *root, const ElenmentType k)
  3. {
  4. if (NULL == root)
  5. return root;
  6. if (!binaryTreeSearch(root,k))//查找删除元素是否存在
  7. {
  8. cout<<"删除失败,未找到"<<endl;
  9. return root;
  10. }
  11. if (k == root->value)//根节点
  12. {
  13. if (root->left!=NULL&&root->right!=NULL)//左右子树都非空
  14. {
  15. if (diff(root) > 0)//左子树更高,在左边删除
  16. {
  17. root->value = tree_max(root->left);//以左子树的最大值替换当前值
  18. root->left = Delete(root->left, root->value);//删除左子树中已经替换上去的节点
  19. }
  20. else//右子树更高,在右边删除
  21. {
  22. root->value = tree_min(root->right);//以右子树的最小值替换当前值
  23. root->right = Delete(root->right, root->value);//删除右子树中已经替换上去的节点
  24. }
  25. }
  26. else//有一个孩子、叶子节点的情况合并
  27. {
  28. Tree * tmp = root;
  29. root = (root->left) ? (root->left) :( root->right);
  30. delete tmp;
  31. tmp = NULL;
  32. }
  33. }
  34. //往左边删
  35. else if (k < root->value)
  36. {
  37. root->left = Delete(root->left, k);
  38. //不满足平衡条件
  39. if (diff(root) < -1)
  40. {
  41. if (diff(root->right) > 0)
  42. {
  43. root = RL_rotate(root);
  44. }
  45. else
  46. {
  47. root = RR_rotate(root);
  48. }
  49. }
  50. }
  51. //往右边删
  52. else
  53. {
  54. root->right = Delete(root->right, k);
  55. //不满足平衡 条件
  56. if (diff(root) > 1)
  57. {
  58. if (diff(root->left) < 0)
  59. {
  60. root = LR_rotate(root);
  61. }
  62. else
  63. {
  64. root = LL_rotate(root);
  65. }
  66. }
  67. }
  68. return root;
  69. }

完整代码如下:

  1. #include<iostream>
  2. using namespace std;
  3. typedef int ElenmentType;
  4. //平衡二叉树的结构
  5. typedef struct AVLNode{
  6. int depth;//深度
  7. struct AVLNode *left;//左孩子
  8. struct AVLNode *right;//右孩子
  9. struct AVLNode *parent;//父结点
  10. ElenmentType value; //
  11. }AVLtree,Tree;
  12. //初始化
  13. Tree* Init(ElenmentType value){
  14. Tree* root=new Tree();
  15. root->parent = NULL;
  16. root->depth = 0;
  17. root->left = root->right = NULL;
  18. root->value=value;
  19. return root;
  20. }
  21. //LL型调整函数,执行右旋
  22. Tree* LL_rotate(Tree *root){
  23. Tree *temp;
  24. temp = root->left;
  25. root->left = temp->right;
  26. temp->right = root;
  27. return temp;
  28. }
  29. //RR型调整函数,执行左旋
  30. Tree* RR_rotate(Tree * root){
  31. Tree* temp;
  32. temp = root->right;
  33. root->right = temp->left;
  34. temp->left = root;
  35. return temp;
  36. }
  37. //LR型调整函数,先左旋转,再右旋转
  38. Tree* LR_rotate(Tree* root){
  39. Tree* temp;
  40. temp = root->left;
  41. root->left =RR_rotate(temp);
  42. return LL_rotate(root);
  43. }
  44. //RL型调整函数,先右旋转,再左旋转
  45. Tree* RL_rotate(Tree* root){
  46. Tree* temp;
  47. temp = root->right;
  48. root->right=LL_rotate(temp);
  49. return RR_rotate(root);
  50. }
  51. //树高
  52. int height(Tree* root)
  53. {
  54. if (root == NULL)
  55. return 0;
  56. int max;
  57. int left=height(root->left);
  58. int right=height(root->right);
  59. if(left>=right)
  60. max=left;
  61. else
  62. max=right;
  63. return max+1;
  64. }
  65. //求叶子节点个数
  66. int GetSumOfLeafNode(Tree* root)
  67. {
  68. if(root == NULL)
  69. return 0;
  70. if(root->left == NULL && root->right == NULL)
  71. return 1;
  72. else
  73. {
  74. return GetSumOfLeafNode(root->left)
  75. + GetSumOfLeafNode(root->right);
  76. }
  77. }
  78. //平衡因子,即当前节点左右子树的差
  79. int diff(Tree* root)
  80. {
  81. return height(root->left) - height(root->right);
  82. }
  83. //平衡操作
  84. Tree* Balance(Tree* root)
  85. {
  86. int balanceFactor = diff(root);//平衡因子(左右子树高度差)
  87. if (balanceFactor > 1)//左子树高于右子树
  88. {
  89. if (diff(root->left) > 0)
  90. //LL的情况
  91. root=LL_rotate(root);
  92. else
  93. //LR的情况
  94. root=LR_rotate(root);
  95. }
  96. else if (balanceFactor < -1)//右子树高于左子树
  97. {
  98. if (diff(root->right) > 0)
  99. //RL的情况
  100. root=RL_rotate(root);
  101. else
  102. //RR的情况
  103. root=RR_rotate(root);
  104. }
  105. return root;
  106. }
  107. //插入结点
  108. Tree* Insert(Tree* root,ElenmentType k )
  109. {
  110. if (NULL == root)
  111. {
  112. root = Init(k);//如果根结点为null,则直接将值为根结点
  113. if(root==NULL)
  114. cout<<"创建失败"<<endl;
  115. return root;
  116. }
  117. else if (k < root->value)
  118. {
  119. root->left = Insert(root->left, k);//递归左子树
  120. root = Balance(root);//平衡操作
  121. }
  122. else if (k>root->value)
  123. {
  124. root->right = Insert(root->right, k);//递归右子树
  125. root = Balance(root);//平衡操作
  126. }
  127. return root;
  128. }
  129. //前序遍历
  130. void displayTree_Pre(Tree* node){
  131. if(node == NULL) return;
  132. cout<<node->value<<" ";
  133. if(node->left != NULL){
  134. displayTree_Pre(node->left);
  135. }
  136. if(node->right != NULL){
  137. displayTree_Pre(node->right);
  138. }
  139. }
  140. //中序遍历
  141. void displayTree_Mid(Tree* node){
  142. if(node == NULL) return;
  143. if(node->left != NULL){
  144. displayTree_Mid(node->left);
  145. }
  146. cout<<node->value<<" ";
  147. if(node->right != NULL){
  148. displayTree_Mid(node->right);
  149. }
  150. }
  151. //后序遍历
  152. void displayTree_Post(Tree* node){
  153. if(node == NULL) return;
  154. if(node->left != NULL){
  155. displayTree_Post(node->left);
  156. }
  157. if(node->right != NULL){
  158. displayTree_Post(node->right);
  159. }
  160. cout<<node->value<<" ";
  161. }
  162. //查找value
  163. Tree* binaryTreeSearch(Tree *node,int value){
  164. if(node->value==value)
  165. return node;
  166. //大于,在左边找
  167. else if(node->value>value){
  168. if(node->left!=NULL)
  169. return binaryTreeSearch(node->left,value);
  170. else return NULL;
  171. }
  172. //否则,在右边找
  173. else{
  174. if(node->right!=NULL)
  175. return binaryTreeSearch(node->right,value);
  176. else
  177. return NULL;
  178. }
  179. }
  180. //平衡二叉树最大值
  181. ElenmentType tree_max(Tree *node){
  182. int value;
  183. value=node->value;
  184. if(node->right!=NULL)
  185. return tree_max(node->right);
  186. else
  187. return value;
  188. }
  189. //平衡二叉树最小值
  190. ElenmentType tree_min(Tree *node){
  191. int value;
  192. value=node->value;
  193. if(node->left!=NULL)
  194. return tree_min(node->left);
  195. else
  196. return value;
  197. }
  198. //删除结点
  199. Tree* Delete(Tree *root, const ElenmentType k)
  200. {
  201. if (NULL == root)
  202. return root;
  203. if (!binaryTreeSearch(root,k))//查找删除元素是否存在
  204. {
  205. cout<<"删除失败,未找到"<<endl;
  206. return root;
  207. }
  208. if (k == root->value)//根节点
  209. {
  210. if (root->left!=NULL&&root->right!=NULL)//左右子树都非空
  211. {
  212. if (diff(root) > 0)//左子树更高,在左边删除
  213. {
  214. root->value = tree_max(root->left);//以左子树的最大值替换当前值
  215. root->left = Delete(root->left, root->value);//删除左子树中已经替换上去的节点
  216. }
  217. else//右子树更高,在右边删除
  218. {
  219. root->value = tree_min(root->right);//以右子树的最小值替换当前值
  220. root->right = Delete(root->right, root->value);//删除右子树中已经替换上去的节点
  221. }
  222. }
  223. else//有一个孩子、叶子节点的情况合并
  224. {
  225. Tree * tmp = root;
  226. root = (root->left) ? (root->left) :( root->right);
  227. delete tmp;
  228. tmp = NULL;
  229. }
  230. }
  231. //往左边删
  232. else if (k < root->value)
  233. {
  234. root->left = Delete(root->left, k);
  235. //不满足平衡条件
  236. if (diff(root) < -1)
  237. {
  238. if (diff(root->right) > 0)
  239. {
  240. root = RL_rotate(root);
  241. }
  242. else
  243. {
  244. root = RR_rotate(root);
  245. }
  246. }
  247. }
  248. //往右边删
  249. else
  250. {
  251. root->right = Delete(root->right, k);
  252. //不满足平衡 条件
  253. if (diff(root) > 1)
  254. {
  255. if (diff(root->left) < 0)
  256. {
  257. root = LR_rotate(root);
  258. }
  259. else
  260. {
  261. root = LL_rotate(root);
  262. }
  263. }
  264. }
  265. return root;
  266. }
  267. int main(){
  268. int a[10]={12,13,55,66,44,77,99,33,46,79};
  269. Tree *root=NULL;
  270. for(int i=0;i<10;i++){
  271. root = Insert(root,a[i]);
  272. }
  273. cout<<"平衡二叉树前序遍历:";
  274. displayTree_Pre(root);
  275. cout<<endl;
  276. cout<<"平衡二叉树中序遍历:";
  277. displayTree_Mid(root);
  278. cout<<endl;
  279. cout<<"平衡二叉树高度:"<<height(root)<<endl;
  280. int value = 33;
  281. cout<<"平衡二叉树最大值:"<<tree_max(root)<<endl;
  282. cout<<"平衡二叉树最小值:"<<tree_min(root)<<endl;
  283. cout<<"平衡二叉树叶子结点:"<<GetSumOfLeafNode(root)<<endl;
  284. Tree* obj;
  285. if((obj=binaryTreeSearch(root,value))==NULL){
  286. cout<<value<<"值不存在"<<endl;
  287. }
  288. else
  289. cout<<value<<"值存在"<<endl;
  290. root = Insert(root,5);
  291. cout<<"插入结点5后,前序遍历:";
  292. displayTree_Pre(root);
  293. cout<<endl;
  294. cout<<"插入结点5后,中序遍历:";
  295. displayTree_Mid(root);
  296. cout<<endl;
  297. int del=79;
  298. if (!binaryTreeSearch(root,del))//查找删除元素是否存在
  299. {
  300. cout<<"删除失败,未找到要删除的结点"<<endl;
  301. }else{
  302. Delete(root,del);
  303. cout<<"删除结点后,前序遍历: ";
  304. displayTree_Pre(root);
  305. cout<<endl;
  306. cout<<"删除结点后,中序遍历: ";
  307. displayTree_Mid(root);
  308. cout<<endl;
  309. }
  310. return 0;
  311. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/862473
推荐阅读
相关标签
  

闽ICP备14008679号