当前位置:   article > 正文

AVL树详解与实现

avl

AVL树首先要弄清它的定义:AVL树是一棵高度平衡的二叉搜索树,它要么是一棵空树,要么是一棵左右子树均为AVL树,且左右子树高度差的绝对值不大于一的二叉搜索树

数据结构教科书介绍的AVL树平衡化旋转共有四种方式:LR左单旋转,RR右单旋转,LRR先左后右双旋转,RLR先右后左双旋转,LR和RR,LRR和RLR互为镜像,若不熟悉请参看数据结构教科书,下面要对保证AVL树插入删除操作正确性的原理进行简单的讨论。

当在AVL树中删除一个节点时,按对二叉搜索树执行删除节点操作时采用的方式找到待删除节点,但由二叉搜索树删除算法(请参看数据结构教科书)可知,待删除节点不一定是实际删除节点,在某些情况下待删除节点没有被实际删除,而是将非待删除节点的实际删除节点的数据域替换带删除节点的数据域,此后删除的是实际被删除的节点而不是带删除节点,当然在另一些情况下,待删除节点就是实际删除节点。这样每当按对二叉搜索树执行删除操作的方式成功删除(注意待删除节点未必被实际删除)AVL树中的待删除节点后,通过指针定位到实际被删除节点的父节点及该父节点的被实际删除节点的子树的根节点,设指向该父节点的指针为parent,指向实际被删除节点的该父节点的子树的根节点的指针为q(可能为NULL),那么分别讨论可知,无论在AVL树中对待删除节点执行删除操作对应删除二叉搜索树中节点时可能出现的哪一种情形,以parent为根的子树总满足以下条件A:

1.以parent指向的节点为根节点的子树在执行删除操作前是AVL树(由AVL树定义)

2.以q指向的节点为根节点的子树在被删除一个节点后经过一系列或不经过平衡化旋转后,其高度相比删除前下降一,并且仍然为AVL树

以此为基础我们来寻找循环不变量

现假设存在一棵以parent指向的节点为根节点的二叉搜索树,在对它的子树执行删除操作前它是AVL树且该树是执行删除操作前原AVL树的一棵子树,

若在parent的左子树或右子树上按对二叉搜索树执行删除的方式删除一个节点后经过一系列或不经过平衡化旋转后,左子树的高度相比于删除前下降一并且仍然为AVL树(即parent树满足条件A),q为指向此时该子树根节点的指针,则对parent树而言有如下几种情形:

情形A

以parent指向的节点为根节点的AVL树A在执行删除前根节点平衡因子为0,在parent的左子树上删除一个节点并做或不做平衡化旋转调整后左子树高度下降一,此时parent平衡因子变为1,由于作删除操作的AVL树A满足条件A,以此为依据根据AVL树定义不难验证这时parent树仍然为AVL树,当然其高度相比于删除前没有任何变化,于是从树A根节点到原AVL树根节点的路径上各节点(除树A根节点)的平衡因子仍然和删除前相同,即这些节点仍然平衡,于是按AVL树的定义从A的根节点的父节点到原树根节点逐层向上递推,最后即得以A根节点到原树父节点的路径上的节点为根节点的子树均为AVL树,当然原树仍然为AVL树,于是可以结束平衡化过程

情形A*

和情形A对称,分析是类似的,此时对树A不做任何平衡化旋转,原树已平衡,结束平衡化过程

情形B

以parent指向的节点为根节点的AVL树A在执行删除前根节点平衡因子为-1,在parent的左子树上删除一个节点并做或不做平衡化旋转调整后左子树高度下降一,此时parent平衡因子变为0,由于作删除操作的AVL树A满足条件A,以此为依据根据AVL树定义不难验证这时parent树仍然为AVL树,且其高度相比于删除节点前下降一,此时不对A做任何平衡化旋转,这样就可以发现树A满足在树A上按对二叉搜索树执行删除的方式删除一个节点后经过一系列或不经过平衡化旋转后,树A的高度相比于删除前下降一并且仍然为AVL树,注意到树A高度降一影响到其根节点父节点平衡因子有可能使其失衡,所以令parent为树A根节点的父节点,q为树A根节点回溯至上一层再按各种情形进行相应的处理。这样做是合理的,因为此时以parent为根的子树(q为parent左子树或右子树根节点)刚好满足条件A,这样就能就各种情形以相同的方式进行同样的处理

情形C

以parent指向的节点为根节点的AVL树A右子树根节点平衡因子为0,在执行删除前根节点平衡因子为1,在parent的左子树上删除一个节点并做或不做平衡化旋转调整后左子树高度下降一,此时parent平衡因子变为2,树A失衡于是对树A做左单旋转,由于作删除操作的AVL树A满足条件A,以此为依据根据AVL树定义不难验证左单旋转后的树A仍然为AVL树,且其高度相比于删除前没有任何变化,于是从树A根节点到原AVL树根节点的路径上各节点(除树A根节点)的平衡因子仍然和删除前相同,即这些节点仍然平衡,于是按AVL树的定义从A的根节点的父节点到原树根节点逐层向上递推,最后即得以A根节点到原树父节点的路径上的节点为根节点的子树均为AVL树,当然原树仍然为AVL树,这样就可以结束平衡化过程

情形C*

和情形C对称,分析是类似的,此时对树A做右单旋转,然后原树已平衡,结束平衡化过程

 情形D

以parent指向的节点为根节点的AVL树A右子树根节点平衡因子为1,在执行删除前根节点平衡因子为1,在parent的左子树上删除一个节点并做或不做平衡化旋转调整后左子树高度下降一,此时parent平衡因子变为2,树A失衡于是对树A做左单旋转。由于作删除操作的AVL树A满足条件A,以此为依据根据AVL树定义不难验证左单旋转后的树A仍然为AVL树,且其高度相比于删除节点前下降一,这样就可以发现树A满足在树A上按对二叉搜索树执行删除的方式删除一个节点后经过一系列或不经过平衡化旋转后,树A的高度相比于删除前下降一并且仍然为AVL树,注意到树A高度降一影响到其根节点父节点平衡因子有可能使其失衡,所以令parent为树A根节点的父节点,q为树A根节点回溯至上一层再按各种情形进行相应的处理。这样做是合理的,因为此时以parent为根的子树(q为parent左子树或右子树根节点)刚好满足条件A,这样就能就各种情形以相同的方式进行同样的处理

情形D*

和情形D对称,分析是类似的,此时对树A做右单旋转,然后回溯至上一层继续平衡化

情形E

以parent指向的节点为根节点的AVL树A右子树根节点平衡因子为-1,在执行删除前根节点平衡因子为1,在parent的左子树上删除一个节点并做或不做平衡化旋转调整后左子树高度下降一,此时parent平衡因子变为2,树A失衡于是对树A做先右后左双旋转。由于作删除操作的AVL树A满足条件A,以此为依据根据AVL树定义不难验证先右后左双旋转后的树A仍然为AVL树,且其高度相比于删除节点前下降一,这样就可以发现树A满足在树A上按对二叉搜索树执行删除的方式删除一个节点后经过一系列或不经过平衡化旋转后,树A的高度相比于删除前下降一并且仍然为AVL树,注意到树A高度降一影响到其根节点父节点平衡因子有可能使其失衡,所以令parent为树A根节点的父节点,q为树A根节点回溯至上一层再按各种情形进行相应的处理。这样做是合理的,因为此时以parent为根的子树(q为parent左子树或右子树根节点)刚好满足条件A,这样就能就各种情形以相同的方式进行同样的处理

情形E*

和情形E对称,分析是类似的,此时对树A做先左后右双旋转,然后回溯至上一层继续平衡化

从以上讨论就可以看出循环不变量了,它就是parent子树满足的条件A,如果parent子树满足条件A且对应A,A* 两种情形,则不做平衡化旋转并结束平衡化,如果对应C,C*两种情形,则做单旋转并结束平衡化,如果对应B,B*两种情形则不做平衡化旋转并回溯至上一层平衡化(以parent父节点为根的子树满足条件A),若对应D,D*两种情形则做单旋转并回溯至上一层平衡化(以parent父节点为根的子树满足条件A),若对应E,E*两种情形,则做双旋转并回溯至上一层平衡化(以parent父节点为根的子树满足条件A).由此可以总结出删除AVL树某节点过程中经历的平衡化过程如下:

从本文开头提及的最初的parent子树开始,该parent子树满足条件A,q为parent子树被删除节点的子树的根节点指针(可能为NULL).

AVL树删除算法(调整平衡因子的细节没有给出,请参考下方代码):

(1)在AVL树上执行二叉搜索树删除算法,之后令parent为实际被删除节点的父节点,q为实际被删节点所在的该父节点的子树的根节点的指针

(2) if(parent子树对应于A,A* C,C*情形)

        A,A*情形,直接转3

        C情形 parent子树左单旋转, 然后转3

        C*情形 parent子树右单旋转, 然后转3

     else

        B,B*情形 如果 parent为根节点转3 否则 q=parent    parent=parent父节点转2

        D情形 parent子树左单旋转 随后如果 parent为根节点转3 否则q=parent    parent=parent父节点 转2

        D*情形 parent子树右单旋转 随后如果 parent为根节点转3 否则q=parent    parent=parent父节点 转2

        E情形 parent子树先右后左双旋转 随后如果 parent为根节点转3 否则q=parent    parent=parent父节点 转2

        E*情形 parent子树先左后右双旋转 随后如果 parent为根节点转3 否则q=parent    parent=parent父节点 转2

(3)结束

在这里发表一些个人看法,一些数据结构教科书上(如数据结构与算法分析:java语言描述)提到AVL树删除算法的正确编写有一定难度,实际上并非如此.从以上算法来看,编程实现时思路的推进完全是线性的,根本没有难度。非要说实现难度大,那也只能是琐碎的编码细节令人抓狂,事实上从

以上算法来看删除算法本质上非常简单,并不复杂,编写代码只需用心就能正确实现删除算法

下面讨论AVL树的插入

插入操作和删除相比更为简单,实现难度更低,分析插入操作还是要先寻找循环不变量

 首先插入新节点后只有新节点父节点至根节点的路径上的节点的平衡因子受影响,以路径上各节点为根的子树的高度要么加一要么不变,即平衡因子要么加减一要么不变。因此路径上各节点的平衡因子在插入新节点后的范围在-2至2之间

按最一般情形考虑,插入新节点(在非空树中插入)后,令parent为新插入节点父节点,q为新插入节点。若插入后parent平衡因子(不是为+-1就是为0)为0,则根据定义不难验证原树已平衡为AVL树,这样就可以结束平衡化过程,若平衡因子为+-1(插入前parent为叶节点),则令q=parent,parent为其父节点,这样parent子树满足条件B:

    q为AVL树    插入前q平衡因子为0,插入后绝对值为1,q高度相比于插入前加一,且此时没有对q或其子树做平衡化旋转

这样设有一棵原AVL树的子树,根节点为parent,parent的按二叉搜索树插入方式插入节点的子树根节点为q,parent满足条件B。根据节点插入parent右子树或左子树加减parent平衡因子,调整parent平衡因子为插入后平衡因子。然后,

如果parent平衡因子为+-1,则插入前为0,且parent高度相比于插入前加一,插入后parent仍然为AVL树,此时不对parent进行平衡化旋转,由于parent插入后高度加一parent父节点的平衡因子受到影响,因此令q=parent,parent=parent父节点,回溯到上一层按所列各情形进行平衡化操作。这样做是合理的,因为根据上述分析回溯到上一层后parent子树满足条件B,所以完全可以按照各情形以相同方式进行相同处理

如果parent平衡因子为0,则插入前parent平衡因子绝对值为1,即新节点在较矮的子树上插入,插入后parent左右子树等高,不难看出插入后parent子树仍为AVL树且高度相比于插入前不变,于是沿从parent父节点到原AVL树根节点的路径层层向上递推即可验证插入后原树仍为AVL树,故此时可结束平衡化过程

若parent平衡因子绝对值为2,则有以下几种情形:

情形一:

插入后parent平衡因子为-2,q平衡因子为-1,即在q的左子树上插入,左子树在插入后高度加一,q为parent左子树,此时直接对parent做右单旋转,根据做平衡化旋转前的parent树满足条件B和AVL树定义可验证旋转后parent仍然为AVL树,且高度相比于插入前不变,这样原树已平衡,直接结束平衡化过程

情形一*

和情形一对称,插入后parent平衡因子为2,q平衡因子为1,即在q的右子树上插入,右子树在插入后高度加一,q为parent右子树,此时对parent做左单旋转并结束平衡化过程

情形二:

插入后parent平衡因子为-2,q平衡因子为1,即在q的右子树上插入,q为parent左子树,q的右子树插入后高度增一,故必有q的右子女p(树C的根)。由于是在子树p上插入,所以p一定为从最初的parent子树的根节点至q的回溯路径上的一个节点,因此插入后p的平衡因子为+-1,插入前为0,因此一定为在p的两棵等高子树之一上插入,插入后子树p的高度状况如上图所示,此时直接对parent做先左后右双旋转,根据做平衡化旋转前的parent树满足条件B和AVL树定义可验证旋转后parent仍然为AVL树,且高度相比于插入前不变,这样原树已平衡,直接结束平衡化过程

情形二*

和情形二对称,分析是类似的,插入后parent平衡因子为2,q平衡因子为-1,即在q的左子树上插入,q为parent右子树,q的左子树插入后高度增一,故必有q的左子女p(树C的根)。由于是在子树p上插入,所以p一定为从最初的parent子树的根节点至q的回溯路径上的一个节点,因此插入后p的平衡因子为+-1,插入前为0,因此一定为在p的两棵等高子树之一上插入,插入后子树p的高度状况如上图所示,此时直接对parent做先右后左双旋转,根据做平衡化旋转前的parent树满足条件B和AVL树定义可验证旋转后parent仍然为AVL树,且高度相比于插入前不变,这样原树已平衡,直接结束平衡化过程

由以上讨论可以看出循环不变量就是parent子树满足的条件B,如果parent子树满足条件B,那么若parent在插入后的平衡因子绝对值为1,则令q=parent   parent=parent父节点  回溯到上一层继续按文中列出的情形进行平衡化,若parent在插入后的平衡因子为0,则直接结束平衡化过程,若parent在插入后的平衡因子绝对值为2,此时若parent子树对应情形一则对parent子树执行右单旋转并结束平衡化过程,对应情形一*则对parent子树执行左单旋转并结束平衡化过程,对应情形二则对parent子树执行先左后右双旋转并结束平衡化过程,对应情形二*则对parent子树执行先右后左双旋转并结束平衡化过程。

根据上述分析按和分析删除操作类似的方式就可以总结出AVL树的插入算法,可以自行分析,这里就不赘述了。

下面是删除与插入操作的具体代码实现,代码中加入判断是否为AVL树的代码(非递归)以检验删除操作的正确性,也就是每次删除插入成功后用判断函数检验删除插入后的二叉树是否为AVL树,从而检验插入删除算法的正确性

  1. #include <stack>
  2. #include <vector>
  3. #include <iostream>
  4. #include <string>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <random>
  8. #include <ctime>
  9. using namespace std;
  10. #define TYPE int
  11. template <typename T>
  12. struct AVLNode //AVL树节点类
  13. {
  14. int bf; //节点平衡因子
  15. T data; //节点数据域
  16. AVLNode* left;
  17. AVLNode* right;
  18. AVLNode(int b, T d) :bf(b), data(d), left(nullptr), right(nullptr) {}
  19. };
  20. template <typename T>
  21. void RotateLR(AVLNode<T>*& ptr) //对以ptr为根的子树执行先左后右双旋转,ptr成为旋转后新树根节点指针
  22. {
  23. AVLNode<T>* p = ptr->left;
  24. AVLNode<T>* q = p->right;
  25. p->right = q->left;
  26. q->left = p;
  27. ptr->left = q->right;
  28. q->right = ptr;
  29. if (q->bf == 0)
  30. {
  31. p->bf = ptr->bf = 0;
  32. }
  33. else
  34. {
  35. if (q->bf == -1)
  36. {
  37. p->bf = 0;
  38. ptr->bf = 1;
  39. }
  40. else
  41. {
  42. p->bf = -1;
  43. ptr->bf = 0;
  44. }
  45. q->bf = 0;
  46. }
  47. ptr = q;
  48. }
  49. template <typename T>
  50. void RotateRL(AVLNode<T>*& ptr) //对以ptr为根的子树执行先右后左双旋转,ptr成为旋转后新树根节点指针
  51. {
  52. AVLNode<T>* p = ptr->right;
  53. AVLNode<T>* q = p->left;
  54. p->left = q->right;
  55. q->right = p;
  56. ptr->right = q->left;
  57. q->left = ptr;
  58. if (q->bf == 0)
  59. {
  60. p->bf = ptr->bf = 0;
  61. }
  62. else
  63. {
  64. if (q->bf == -1)
  65. {
  66. p->bf = 1;
  67. ptr->bf = 0;
  68. }
  69. else
  70. {
  71. p->bf = 0;
  72. ptr->bf = -1;
  73. }
  74. q->bf = 0;
  75. }
  76. ptr = q;
  77. }
  78. template <typename T>
  79. void RotateR(AVLNode<T>*& ptr) //对以ptr为根的子树执行右单旋转,ptr成为旋转后新树根节点指针
  80. {
  81. AVLNode<T>* p = ptr->left;
  82. ptr->left = p->right;
  83. p->right = ptr;
  84. if (p->bf == -1)
  85. {
  86. p->bf = ptr->bf = 0;
  87. }
  88. else
  89. {
  90. p->bf = 1;
  91. }
  92. ptr = p;
  93. }
  94. template <typename T>
  95. void RotateL(AVLNode<T>*& ptr) //对以ptr为根的子树执行左单旋转, ptr成为旋转后新树根节点指针
  96. {
  97. AVLNode<T>*p = ptr->right;
  98. ptr->right = p->left;
  99. p->left = ptr;
  100. if (p->bf == 0)
  101. {
  102. p->bf = -1;
  103. ptr->bf = 1;
  104. }
  105. else
  106. {
  107. ptr->bf = p->bf = 0;
  108. }
  109. ptr = p;
  110. }
  111. template <typename T>
  112. int Searchd(AVLNode<T>* ptr, int d)
  113. {
  114. if (d == 2)
  115. return 0;
  116. else
  117. {
  118. if (d == 1)
  119. {
  120. if (ptr->right == nullptr)
  121. return 0;
  122. else
  123. return 2;
  124. }
  125. else
  126. {
  127. if (ptr->left != nullptr)
  128. return 1;
  129. else
  130. {
  131. if (ptr->right != nullptr)
  132. return 2;
  133. else
  134. return 0;
  135. }
  136. }
  137. }
  138. }
  139. template <typename T>
  140. bool isAVL(AVLNode<T>* root) //判断以root为根节点的二叉树是否为AVL树
  141. {
  142. struct memory
  143. {
  144. AVLNode<T>* p;
  145. int direction;
  146. T lmin;
  147. int lh = 0; //节点左子树高度
  148. memory(AVLNode<T>* p, int d) :p(p), direction(d) {}
  149. };
  150. T rmin;
  151. T rmax;
  152. T lmax;
  153. int rh;
  154. int d = 0;
  155. AVLNode<T>* ptr = root;
  156. AVLNode<T>* const dest = ptr;
  157. stack<memory> arrange;
  158. bool TF = false;
  159. while (true)
  160. {
  161. if (Searchd(ptr, d) == 0)
  162. {
  163. if (ptr == dest)
  164. {
  165. if (d == 0)
  166. return true;
  167. }
  168. if (d == 0)
  169. {
  170. if (arrange.top().direction == 1)
  171. {
  172. arrange.top().lh = 1;
  173. arrange.top().lmin = ptr->data;
  174. lmax = ptr->data;
  175. }
  176. else
  177. {
  178. rh = 1;
  179. rmin = ptr->data;
  180. rmax = ptr->data;
  181. }
  182. }
  183. else
  184. {
  185. if (d == 1)
  186. {
  187. if (lmax >= ptr->data)
  188. {
  189. cout << "当前树非二叉搜索树,也非AVL树" << endl;
  190. return false;
  191. }
  192. if (arrange.top().lh > 1)
  193. {
  194. cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl;
  195. return false;
  196. }
  197. if (ptr == dest)
  198. return true;
  199. T lmin = arrange.top().lmin;
  200. int lh = arrange.top().lh;
  201. arrange.pop();
  202. if (arrange.top().direction == 1)
  203. {
  204. arrange.top().lmin = lmin;
  205. arrange.top().lh = lh + 1;
  206. lmax = ptr->data;
  207. }
  208. else
  209. {
  210. rmin = lmin;
  211. rmax = ptr->data;
  212. rh = lh + 1;
  213. }
  214. }
  215. else
  216. {
  217. if (rmin <= ptr->data)
  218. {
  219. cout << "当前树非二叉搜索树,也非AVL树" << endl;
  220. return false;
  221. }
  222. if (abs(rh - arrange.top().lh) > 1)
  223. {
  224. cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl;
  225. return false;
  226. }
  227. if (ptr == dest)
  228. return true;
  229. if (ptr->left == nullptr)
  230. {
  231. arrange.pop();
  232. if (arrange.top().direction == 1)
  233. {
  234. arrange.top().lmin = ptr->data;
  235. lmax = rmax;
  236. arrange.top().lh = rh + 1;
  237. }
  238. else
  239. {
  240. rmin = ptr->data;
  241. ++rh;
  242. }
  243. }
  244. else
  245. {
  246. T lmin = arrange.top().lmin;
  247. int lh = arrange.top().lh;
  248. arrange.pop();
  249. if (arrange.top().direction == 1)
  250. {
  251. arrange.top().lmin = lmin;
  252. arrange.top().lh = max(lh, rh) + 1;
  253. lmax = rmax;
  254. }
  255. else
  256. {
  257. rmin = lmin;
  258. rh = max(lh, rh) + 1;
  259. }
  260. }
  261. }
  262. }
  263. ptr = arrange.top().p;
  264. d = arrange.top().direction;
  265. }
  266. else
  267. {
  268. AVLNode<T>* interval = nullptr;
  269. if (d == 0)
  270. {
  271. arrange.push(memory(ptr, Searchd(ptr, d)));
  272. if (arrange.top().direction == 1)
  273. ptr = ptr->left;
  274. else
  275. ptr = ptr->right;
  276. }
  277. else
  278. {
  279. if (ptr->data <= lmax)
  280. {
  281. cout << "当前树非二叉搜索树,也非AVL树" << endl;
  282. return false;
  283. }
  284. arrange.top().direction = 2;
  285. ptr = ptr->right;
  286. }
  287. d = 0;
  288. }
  289. }
  290. }
  291. template <typename T>
  292. void linkWithUpper(AVLNode<T>* parent, AVLNode<T>* original, AVLNode<T>* _new)
  293. {
  294. if (original == parent->left)
  295. {
  296. parent->left = _new;
  297. }
  298. else
  299. {
  300. parent->right = _new;
  301. }
  302. }
  303. template <typename T>
  304. bool executeDelete(AVLNode<T>*& parent, AVLNode<T>*& q, AVLNode<T>* p, AVLNode<T>* left_or_right, stack<AVLNode<T>*>& stackforflashback)
  305. {
  306. if (stackforflashback.empty()) //被删节点有父节点
  307. {
  308. parent = left_or_right;
  309. delete p; //删除被删节点后原AVL树恢复平衡,parent为根节点结束
  310. return true;
  311. }
  312. parent = stackforflashback.top();
  313. stackforflashback.pop();
  314. if (parent->left == p)
  315. parent->left = left_or_right; //将被删节点左子树或右子树链接至被删节点父节点相应链指针,并删除被删节点
  316. else
  317. parent->right = left_or_right;
  318. q = left_or_right; //parent为需要做或不做平衡化旋转的第一棵子树根节点指针,q为该子树左子树或右子树根节点指针
  319. delete p;
  320. return false;
  321. }
  322. template <typename T>
  323. void executeDelete(AVLNode<T>*& q, AVLNode<T>* p, AVLNode<T>*& left_or_right)
  324. {
  325. left_or_right = q->right; //left_o_right为parent->left时用该节点数据域替换被删节点数据域,将其右子树链接至其父节点左链指针,随后删除该节点
  326. p->data = q->data; //left_o_right为p->right时用被删节点右子女数据域替换被删节点指针域,将右子女右子树链接至被删节点右链指针,并删除右子女
  327. delete q;
  328. q = left_or_right; //left_o_right为parent->left时parent为需要做或不做平衡化旋转的第一棵子树根节点指针,q为该子树左子树根节点指针
  329. }
  330. template <typename T>
  331. AVLNode<T>* DelAVL(AVLNode<T>* root, T key) //在以root为根节点的AVL树中删除关键码key
  332. {
  333. //AVL树的删除
  334. AVLNode<T>* p = root;
  335. stack<AVLNode<T>*> stackforflashback;
  336. while (p != nullptr) //搜索被删除节点,同时将回溯路径记录在栈中
  337. {
  338. if (p->data == key)
  339. break;
  340. else
  341. {
  342. stackforflashback.push(p);
  343. if (key < p->data)
  344. {
  345. p = p->left;
  346. }
  347. else
  348. {
  349. p = p->right;
  350. }
  351. }
  352. }
  353. if (p != nullptr) //被删除节点存在,被p指向
  354. {
  355. AVLNode<T>* parent = nullptr;
  356. AVLNode<T>* q = nullptr;
  357. if (p->left != nullptr && p->right != nullptr) //被删节点左右子树均存在
  358. {
  359. q = p->right;
  360. parent = p;
  361. if (q->left != nullptr) //被删节点右子树根节点有左子树
  362. {
  363. while (q->left != nullptr) //在被删节点右子树根节点左子树中搜索中序遍历的第一个节点,同时用栈记录回溯路径
  364. {
  365. stackforflashback.push(parent);
  366. parent = q;
  367. q = q->left;
  368. }
  369. executeDelete(q, p, parent->left);
  370. }
  371. else
  372. executeDelete(q, p, p->right);
  373. }
  374. else
  375. {
  376. if (p->left != nullptr) //被删节点左子树不空,右子树空
  377. {
  378. if (executeDelete(parent, q, p, p->left, stackforflashback))
  379. return parent;
  380. }
  381. else if (p->right != nullptr) //处理过程和以上情形完全对称
  382. {
  383. if (executeDelete(parent, q, p, p->right, stackforflashback))
  384. return parent;
  385. }
  386. else //被删节点为叶节点
  387. {
  388. if (executeDelete(parent, q, p, static_cast<AVLNode<T>*>(nullptr), stackforflashback))
  389. return parent;
  390. }
  391. }
  392. bool TF = false;
  393. if (parent->right == nullptr && parent->left == nullptr)
  394. {
  395. parent->bf = 0;
  396. if (stackforflashback.empty())
  397. return root;
  398. q = parent;
  399. parent = stackforflashback.top();
  400. stackforflashback.pop();
  401. }
  402. bool before;
  403. do
  404. {
  405. if (TF == true)
  406. {
  407. if (!before)
  408. {
  409. linkWithUpper(stackforflashback.top(), q, parent);
  410. if (parent->bf != 0)
  411. return root;
  412. }
  413. q = parent;
  414. parent = stackforflashback.top();
  415. stackforflashback.pop();
  416. }
  417. else
  418. {
  419. TF = true;
  420. }
  421. bool l = parent->left == q;
  422. if (parent->bf == 0)
  423. {
  424. if (l)
  425. parent->bf = 1; //情形a
  426. else
  427. parent->bf = -1; //情形a*
  428. return root;
  429. }
  430. if (l ? parent->bf == 1 : parent->bf == -1)
  431. {
  432. q = parent;
  433. if (l)
  434. {
  435. p = parent->right;
  436. if (p->bf != -1)
  437. RotateL(parent); //对以parent为根的子树执行左单旋转 //情形c //情形d //对以parent为根的子树执行左单旋转
  438. else //情形e
  439. RotateRL(parent);//对以parent为根的子树执行先右后左双旋转
  440. }
  441. else
  442. {
  443. p = parent->left;
  444. if (p->bf != 1) //情形c*
  445. RotateR(parent);//对以parent为根的子树执行右单旋转 //情形d* //对以parent为根的子树执行右单旋转
  446. else //情形e*
  447. RotateLR(parent);//对以parent为根的子树执行先左后右双旋转
  448. }
  449. before = false;
  450. }
  451. else
  452. {
  453. before = true;
  454. }
  455. if (before)
  456. parent->bf = 0;
  457. } while (stackforflashback.empty() == false);
  458. return parent; //原AVL树已恢复平衡,返回根节点
  459. }
  460. else
  461. {
  462. cout << "AVL树中不存在要删除的数据元素,删除失败" << endl;
  463. return nullptr;
  464. }
  465. }
  466. template <typename T>
  467. AVLNode<T>* InsertAVL(AVLNode<T>* root, T key)
  468. {
  469. //AVL树的插入
  470. if (root == nullptr)
  471. return new AVLNode<T>(0, key);
  472. else
  473. {
  474. stack<AVLNode<T>*> stackforflashback;
  475. AVLNode<T>* p = root;
  476. while (p != nullptr) //搜索插入位置
  477. {
  478. stackforflashback.push(p);
  479. if (key < p->data)
  480. p = p->left;
  481. else if (key > p->data)
  482. p = p->right;
  483. else
  484. {
  485. cout << "要插入的关键字在AVL树中已存在,插入失败" << endl;
  486. return nullptr;
  487. }
  488. }
  489. p = new AVLNode<T>(0, key);
  490. if (key < stackforflashback.top()->data)
  491. {
  492. stackforflashback.top()->left = p; //新节点插入并调整父节点平衡因子
  493. }
  494. else
  495. {
  496. stackforflashback.top()->right = p;
  497. }
  498. AVLNode<T>* parent = nullptr;
  499. while (stackforflashback.empty() == false)
  500. {
  501. parent = stackforflashback.top();
  502. stackforflashback.pop();
  503. if (parent->left == p)
  504. --parent->bf;
  505. else
  506. ++parent->bf;
  507. if (parent->bf == 0)
  508. return root; //已平衡,返回根节点
  509. else if (parent->bf == -1 || parent->bf == 1)
  510. p = parent; //以parent为根的子树已平衡其高度加一回溯至父节点
  511. else
  512. {
  513. AVLNode<T>* q = parent;
  514. if (parent->bf == -2)
  515. {
  516. if (p->bf == 1)
  517. RotateLR(parent);//对parent为根的子树执行先左后右双旋转 //已平衡
  518. else
  519. RotateR(parent);//对以parent为根子树执行右单旋转 //已平衡
  520. }
  521. else
  522. {
  523. if (p->bf == -1)
  524. {
  525. RotateRL(parent);//对parent为根的子树执行先右后左双旋转 //已平衡
  526. }
  527. else
  528. {
  529. RotateL(parent);//对以parent为根的子树执行左单旋转 //已平衡
  530. }
  531. }
  532. if (stackforflashback.empty() == false)
  533. {
  534. linkWithUpper(stackforflashback.top(), q, parent);
  535. return root; //返回恢复平衡的AVL树根节点
  536. }
  537. return parent;
  538. }
  539. }
  540. return p; //原AVL树已平衡,返回根节点
  541. }
  542. }
  543. template <typename T>
  544. struct memory
  545. {
  546. AVLNode<T>* p;
  547. int direction;
  548. int last;
  549. memory(AVLNode<T>* p, int d, int l) :p(p), direction(d), last(l) {}
  550. };
  551. template <typename T>
  552. void set(stack<memory<T>>& arrange)
  553. {
  554. if (arrange.top().last == 0)
  555. {
  556. if (arrange.top().direction == 1)
  557. {
  558. arrange.top().last = 1;
  559. }
  560. else
  561. {
  562. cout << " ,";
  563. arrange.top().last = 2;
  564. }
  565. }
  566. else
  567. {
  568. cout << ",";
  569. arrange.top().last = 2;
  570. }
  571. }
  572. template <typename T>
  573. void output(AVLNode<T>* ptr) //输出以ptr为根的AVL树对应的广义表形式
  574. {
  575. int d = 0;
  576. AVLNode<T>* const dest = ptr;
  577. stack<memory<T>> arrange;
  578. while (true)
  579. {
  580. if (Searchd(ptr, d) == 0)
  581. {
  582. if (ptr == dest)
  583. {
  584. if (d == 0)
  585. cout << ptr->data << "(";
  586. else
  587. {
  588. if (arrange.top().last == 1)
  589. cout << ", ";
  590. }
  591. cout << ")";
  592. break;
  593. }
  594. else
  595. {
  596. if (d == 0)
  597. {
  598. set(arrange);
  599. cout << ptr->data;
  600. }
  601. else
  602. {
  603. if (arrange.top().last != 2)
  604. cout << ", ";
  605. cout << ")";
  606. arrange.pop();
  607. }
  608. ptr = arrange.top().p;
  609. d = arrange.top().direction;
  610. }
  611. }
  612. else
  613. {
  614. AVLNode<T>* interval = nullptr;
  615. if (d == 0)
  616. {
  617. if (arrange.empty() == false)
  618. set(arrange);
  619. cout << ptr->data << "(";
  620. arrange.push(memory<T>(ptr, Searchd(ptr, d), 0));
  621. if (arrange.top().direction == 1)
  622. ptr = ptr->left;
  623. else
  624. ptr = ptr->right;
  625. }
  626. else
  627. {
  628. arrange.top().direction = 2;
  629. ptr = ptr->right;
  630. }
  631. d = 0;
  632. }
  633. }
  634. }
  635. void printNULL(size_t num)
  636. {
  637. for (size_t o = 1; o <= num; ++o)
  638. cout << " ";
  639. cout << "NULL" << endl;
  640. }
  641. template <typename T>
  642. void printAVLTree(AVLNode<T>* root, size_t offset)
  643. {
  644. if (root == nullptr)
  645. cout << "NULL空树" << endl;;
  646. for (int i = 1; i <= offset; ++i)
  647. cout << " ";
  648. string s = to_string(root->data);
  649. offset += s.size() + 4;
  650. cout << s << ":" << "bf=";
  651. if (root->bf == -1)
  652. {
  653. cout << "-1";
  654. offset += 2;
  655. }
  656. else if (root->bf == 1)
  657. {
  658. cout << "+1";
  659. offset += 2;
  660. }
  661. else
  662. {
  663. cout << "0";
  664. offset += 1;
  665. }
  666. cout << endl;
  667. if (root->left == nullptr)
  668. {
  669. if (root->right != nullptr)
  670. {
  671. printNULL(offset);
  672. printAVLTree(root->right, offset);
  673. }
  674. }
  675. else
  676. {
  677. printAVLTree(root->left, offset);
  678. if (root->right == nullptr)
  679. {
  680. printNULL(offset);
  681. }
  682. else
  683. printAVLTree(root->right, offset);
  684. }
  685. }
  686. int main()
  687. {
  688. const int N = 2000;
  689. //vector<TYPE> insertvalue{ 13, 5, 3, 2, 1, 4, 10, 8, 7, 6, 9, 11, 12, 16, 14, 15, 18, 17, 20, 19 };
  690. vector<TYPE> insertvalue;
  691. for (int i = 1; i <= N; ++i)
  692. {
  693. insertvalue.push_back(i);
  694. }
  695. shuffle(insertvalue.begin(), insertvalue.end(), default_random_engine());
  696. AVLNode<TYPE>* root = nullptr;
  697. for (vector<TYPE>::const_iterator p = insertvalue.cbegin(); p != insertvalue.cend(); ++p)
  698. {
  699. cout << "插入节点" << *p << endl;
  700. root = InsertAVL(root, *p);
  701. //output(root);
  702. cout << endl;
  703. if (isAVL(root) == true)
  704. {
  705. cout << "当前树是AVL树";
  706. cout << endl;
  707. }
  708. else
  709. {
  710. cerr << "错误当前树不是AVL树!" << endl;
  711. exit(0);
  712. }
  713. }
  714. cout << endl;
  715. //cout << "插入完成后删除前AVL树为:" << endl;
  716. //printAVLTree(root, 0);
  717. //cout << "插入完成后删除前AVL树对应的广义表形式为:" << endl;
  718. //output(root);
  719. cout << endl;
  720. cout << endl;
  721. for (vector<TYPE>::const_iterator p = insertvalue.cbegin(); p != insertvalue.cend(); ++p)
  722. {
  723. cout << "删除节点" << *p << endl;
  724. root = DelAVL(root, *p);
  725. if (root != nullptr)
  726. {
  727. //printAVLTree(root, 0);
  728. cout << endl;
  729. if (isAVL(root) == true)
  730. {
  731. cout << "当前树是AVL树";
  732. cout << endl;
  733. }
  734. else
  735. {
  736. cerr << "错误当前树不是AVL树!" << endl;
  737. exit(0);
  738. }
  739. }
  740. else
  741. cout << "NULL";
  742. cout << endl;
  743. }
  744. return 0;
  745. }

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

闽ICP备14008679号