对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 "stdafx.h" 2 #include <stack> 3 #include <vector> 4 #include <iostream> 5 #include <string> 6 #include <cmath> 7 #include <algorithm> 8 using namespace std; 9 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 21 template <typename T> 22 void RotateLR(AVLNode<T> *&ptr) //对以ptr为根的子树执行先左后右双旋转,ptr成为旋转后新树根节点指针 23 { 24 AVLNode<T> *p = ptr->left; 25 AVLNode<T> *q = p->right; 26 p->right = q->left; 27 q->left = p; 28 ptr->left = q->right; 29 q->right = ptr; 30 if (q->bf == 0) 31 { 32 p->bf = ptr->bf = 0; 33 } 34 else 35 { 36 if (q->bf == -1) 37 { 38 p->bf = 0; 39 ptr->bf = 1; 40 } 41 else 42 { 43 p->bf = -1; 44 ptr->bf = 0; 45 } 46 q->bf = 0; 47 } 48 ptr = q; 49 } 50 51 template <typename T> 52 void RotateRL(AVLNode<T> *&ptr) //对以ptr为根的子树执行先右后左双旋转,ptr成为旋转后新树根节点指针 53 { 54 AVLNode<T> *p = ptr->right; 55 AVLNode<T> *q = p->left; 56 p->left = q->right; 57 q->right = p; 58 ptr->right = q->left; 59 q->left = ptr; 60 if (q->bf == 0) 61 { 62 p->bf = ptr->bf = 0; 63 } 64 else 65 { 66 if (q->bf == -1) 67 { 68 p->bf = 1; 69 ptr->bf = 0; 70 } 71 else 72 { 73 p->bf = 0; 74 ptr->bf = -1; 75 } 76 q->bf = 0; 77 } 78 ptr = q; 79 } 80 81 template <typename T> 82 void RotateR(AVLNode<T> *&ptr) //对以ptr为根的子树执行右单旋转,ptr成为旋转后新树根节点指针 83 { 84 AVLNode<T> *p = ptr->left; 85 ptr->left = p->right; 86 p->right = ptr; 87 if (p->bf == -1) 88 { 89 p->bf = ptr->bf = 0; 90 } 91 else 92 { 93 p->bf = 1; 94 } 95 ptr = p; 96 } 97 98 template <typename T> 99 void RotateL(AVLNode<T> *&ptr) ////对以ptr为根的子树执行左单旋转,ptr成为旋转后新树根节点指针 100 { 101 AVLNode<T> *p = ptr->right; 102 ptr->right = p->left; 103 p->left = ptr; 104 if (p->bf == 0) 105 { 106 p->bf = -1; 107 ptr->bf = 1; 108 } 109 else 110 { 111 ptr->bf = p->bf = 0; 112 } 113 ptr = p; 114 } 115 116 template <typename T> 117 bool isAVL(AVLNode<T> *root) //判断以root为根节点的二叉树是否为AVL树 118 { 119 struct temp 120 { 121 T lmin; //节点左子树中最小节点值 122 T lmax; //节点左子树中最大节点值 123 T rmin; //节点右子树中最小节点值 124 T rmax; //节点右子树中最大节点值 125 }; 126 struct memory 127 { 128 AVLNode<T> *p; 129 int direction; 130 temp minmax; 131 int lh= 0; //节点左子树高度 132 int rh= 0; //节点右子树高度 133 memory(AVLNode<T> *p, int d) :p(p), direction(d) {} 134 }; 135 int d = 0; 136 AVLNode<T> *ptr = root; 137 AVLNode<T> *const dest = ptr; 138 stack<memory> arrange; 139 bool TF = false; 140 while (true) 141 { 142 if (Searchd(ptr, d) == 0) 143 { 144 if (ptr == dest) 145 { 146 if (d == 0) 147 return true; 148 else 149 { 150 if (ptr->left == nullptr || ptr->right != nullptr) 151 { 152 if (ptr->data < arrange.top().minmax.rmin) 153 { 154 if (abs(arrange.top().rh - arrange.top().lh) > 1) 155 { 156 cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl; 157 return false; 158 } 159 arrange.pop(); 160 } 161 else 162 { 163 cout << "当前树非二叉搜索树,也非AVL树" << endl; 164 return false; 165 } 166 } 167 else 168 { 169 if (ptr->data > arrange.top().minmax.lmax) 170 { 171 if (abs(arrange.top().rh - arrange.top().lh) > 1) 172 { 173 cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl; 174 return false; 175 } 176 arrange.pop(); 177 } 178 else 179 { 180 cout << "当前树非二叉搜索树,也非AVL树" << endl; 181 return false; 182 } 183 } 184 return true; 185 } 186 } 187 else 188 { 189 if (d == 0) 190 { 191 if (arrange.top().direction == 1) 192 { 193 arrange.top().lh = 1; 194 arrange.top().minmax.lmin = ptr->data; 195 arrange.top().minmax.lmax = ptr->data; 196 } 197 else 198 { 199 arrange.top().rh = 1; 200 arrange.top().minmax.rmin = ptr->data; 201 arrange.top().minmax.rmax = ptr->data; 202 } 203 } 204 else 205 { 206 if (ptr->left == nullptr || ptr->right != nullptr) 207 { 208 if (ptr->data < arrange.top().minmax.rmin) 209 { 210 temp temp1 = arrange.top().minmax; 211 int leftheight = arrange.top().lh; 212 int rightheight = arrange.top().rh; 213 arrange.pop(); 214 215 if (arrange.top().direction == 1) 216 { 217 if (ptr->left == nullptr) 218 { 219 arrange.top().minmax.lmin = ptr->data; 220 } 221 else 222 { 223 arrange.top().minmax.lmin = temp1.lmin; 224 } 225 arrange.top().minmax.lmax = temp1.rmax; 226 227 if (abs(rightheight - leftheight) > 1) 228 { 229 cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl; 230 return false; 231 } 232 else 233 { 234 arrange.top().lh = max(leftheight, rightheight) + 1; 235 } 236 } 237 else 238 { 239 if (ptr->left == nullptr) 240 { 241 arrange.top().minmax.rmin = ptr->data; 242 } 243 else 244 { 245 arrange.top().minmax.rmin = temp1.lmin; 246 } 247 arrange.top().minmax.rmax = temp1.rmax; 248 249 if (abs(rightheight - leftheight) > 1) 250 { 251 cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl; 252 return false; 253 } 254 else 255 { 256 arrange.top().rh = max(leftheight, rightheight) + 1; 257 } 258 } 259 } 260 else 261 { 262 cout << "当前树非二叉搜索树,也非AVL树" << endl; 263 return false; 264 } 265 } 266 else 267 { 268 if (ptr->data > arrange.top().minmax.lmax) 269 { 270 temp temp1 = arrange.top().minmax; 271 int leftheight = arrange.top().lh; 272 int rightheight = arrange.top().rh; 273 arrange.pop(); 274 if (arrange.top().direction == 1) 275 { 276 arrange.top().minmax.lmin = temp1.lmin; 277 arrange.top().minmax.lmax = ptr->data; 278 279 if (abs(rightheight - leftheight) > 1) 280 { 281 cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl; 282 return false; 283 } 284 else 285 { 286 arrange.top().lh = max(leftheight, rightheight) + 1; 287 } 288 } 289 else 290 { 291 arrange.top().minmax.rmin = temp1.lmin; 292 arrange.top().minmax.rmax = ptr->data; 293 294 if (abs(rightheight - leftheight) > 1) 295 { 296 cout << "存在左右子树高度差绝对值大于一的子树,原树非AVL树" << endl; 297 return false; 298 } 299 else 300 { 301 arrange.top().rh = max(leftheight, rightheight) + 1; 302 } 303 } 304 } 305 else 306 { 307 cout << "当前树非二叉搜索树,也非AVL树" << endl; 308 return false; 309 } 310 } 311 } 312 ptr = arrange.top().p; 313 d = arrange.top().direction; 314 } 315 } 316 else 317 { 318 AVLNode<T> *interval = nullptr; 319 if (d == 0) 320 { 321 arrange.push(memory(ptr, Searchd(ptr, d))); 322 if (arrange.top().direction == 1) 323 interval = ptr->left; 324 else 325 interval = ptr->right; 326 } 327 else 328 { 329 if (!(ptr->data > arrange.top().minmax.lmax)) 330 { 331 cout << "当前树非二叉搜索树,也非AVL树" << endl; 332 return false; 333 } 334 arrange.top().direction = 2; 335 interval = ptr->right; 336 } 337 d = 0; 338 ptr = interval; 339 } 340 } 341 } 342 343 template <typename T> 344 AVLNode<T> *DelAVL(AVLNode<T> *root, T key) //在以root为根节点的AVL树中删除关键码key 345 { 346 //AVL树的删除 347 AVLNode<T> *p = root; 348 stack<AVLNode<T> *> stackforflashback; 349 while (p != nullptr) //搜索被删除节点,同时将回溯路径记录在栈中 350 { 351 if (p->data == key) 352 break; 353 else 354 { 355 stackforflashback.push(p); 356 if (key < p->data) 357 { 358 p = p->left; 359 } 360 else 361 { 362 p = p->right; 363 } 364 } 365 } 366 367 if (p != nullptr) //被删除节点存在,被p指向 368 { 369 AVLNode<T> *parent = nullptr; 370 AVLNode<T> *q = nullptr; 371 if (p->left != nullptr && p->right != nullptr) //被删节点左右子树均存在 372 { 373 q = p->right; 374 if (q->left != nullptr) //被删节点右子树根节点有左子树 375 { 376 parent = p; 377 stackforflashback.push(parent); 378 while (q->left != nullptr) //在被删节点右子树根节点左子树中搜索中序遍历的第一个节点,同时用栈记录回溯路径 379 { 380 parent = q; 381 q = q->left; 382 if (q->left != nullptr) 383 stackforflashback.push(parent); 384 } 385 parent->left = q->right; //用该节点数据域替换被删节点数据域,将其右子树链接至其父节点左链指针,随后删除该节点 386 p->data = q->data; 387 delete q; 388 q = parent->left; //parent为需要做或不做平衡化旋转的第一棵子树根节点指针,q为该子树左子树根节点指针 389 390 } 391 else 392 { 393 p->right = q->right; //用被删节点右子女数据域替换被删节点指针域,将右子女右子树链接至被删节点右链指针,并删除右子女 394 p->data = q->data; 395 delete q; 396 parent = p; 397 q = p->right; //parent为需要做或不做平衡化旋转的第一棵子树根节点指针,q为该子树左子树根节点指针 398 } 399 } 400 else 401 { 402 if (p->left != nullptr) //被删节点左子树不空,右子树空 403 { 404 if (stackforflashback.empty() == false) //被删节点有父节点 405 { 406 parent = stackforflashback.top(); 407 stackforflashback.pop(); 408 if (parent->left == p) 409 { 410 parent->left = p->left; 411 delete p; 412 q = parent->left; 413 } //将被删节点左子树链接至被删节点父节点相应链指针,并删除被删节点 414 else 415 { 416 parent->right = p->left; 417 delete p; 418 q = parent->right; 419 } //parent为需要做或不做平衡化旋转的第一棵子树根节点指针,q为该子树左子树根节点指针 420 } 421 else 422 { 423 parent = p->left; 424 delete p; //删除被删节点后原AVL树恢复平衡,parent为根节点结束 425 return parent; 426 } 427 } 428 else if (p->right != nullptr) //处理过程和以上情形完全对称 429 { 430 if (stackforflashback.empty() == false) 431 { 432 parent = stackforflashback.top(); 433 stackforflashback.pop(); 434 if (parent->left == p) 435 { 436 parent->left = p->right; 437 delete p; 438 q = parent->left; 439 } 440 else 441 { 442 parent->right = p->right; 443 delete p; 444 q = parent->right; 445 } //parent为需要做或不做平衡化旋转的第一棵子树根节点指针,q为该子树左子树根节点指针 446 } 447 else 448 { 449 parent = p->right; 450 delete p; //删除被删节点后原AVL树恢复平衡,parent为根节点结束 451 return parent; 452 } 453 } 454 else //被删节点为叶节点 455 { 456 if (stackforflashback.empty() == false) //被删叶节点有父节点 457 { 458 parent = stackforflashback.top(); 459 stackforflashback.pop(); 460 if (parent->left == p) 461 { 462 parent->left = nullptr; 463 delete p; 464 q = parent->left; 465 } 466 else //删除叶节点并将其父节点对应指针域置空 467 { 468 parent->right = nullptr; 469 delete p; 470 q = parent->right; 471 } //parent为需要做或不做平衡化旋转的第一棵子树根节点指针,q为该子树左子树根节点指针 472 } 473 else 474 { 475 parent = nullptr; 476 delete p; //删除被删节点后原AVL树恢复平衡,parent为根节点结束 477 return parent; 478 } 479 } 480 } 481 bool TF = false; 482 do 483 { 484 if (TF == true) 485 stackforflashback.pop(); 486 else 487 TF = true; 488 489 if ((parent->bf == 1 || parent->bf == -1) && q == nullptr && parent->right == nullptr && parent->left == nullptr) 490 { 491 parent->bf = 0; 492 if (stackforflashback.empty() == false) 493 { 494 q = parent; 495 parent = stackforflashback.top(); 496 continue; 497 } 498 else 499 { 500 return root; 501 } 502 503 } 504 505 if (parent->left == q) 506 { 507 if (parent->bf == 0) 508 { 509 parent->bf = 1; //情形a 510 return root; 511 } 512 else if (parent->bf == -1) 513 { 514 parent->bf = 0; 515 if (stackforflashback.empty() == false) 516 { 517 q = parent; 518 parent = stackforflashback.top(); 519 continue; //情形b 520 } 521 else 522 { 523 return root; 524 } 525 } 526 else 527 { 528 p = parent->right; 529 q = parent; 530 if (p->bf == 0) 531 { //情形c 532 if (stackforflashback.empty() == false) 533 { 534 RotateL(parent);//对以parent为根的子树执行左单旋转 535 if (q == stackforflashback.top()->left) 536 { 537 stackforflashback.top()->left = parent; 538 } 539 else 540 { 541 stackforflashback.top()->right = parent; 542 } 543 } 544 else 545 { 546 RotateL(parent);//对以parent为根的子树执行左单旋转 547 } 548 if (q == root) 549 { 550 return parent; 551 } 552 else 553 { 554 return root; 555 } 556 } 557 else if (p->bf == 1) //情形d 558 { 559 RotateL(parent);//对以parent为根的子树执行左单旋转 560 } 561 else //情形e 562 { 563 RotateRL(parent);//对以parent为根的子树执行先右后左双旋转 564 } 565 566 if (stackforflashback.empty() == false) 567 { 568 if (q == stackforflashback.top()->left) 569 { 570 stackforflashback.top()->left = parent; 571 } 572 else 573 { 574 stackforflashback.top()->right = parent; 575 } 576 q = parent; 577 parent = stackforflashback.top(); 578 } 579 else 580 { 581 q = parent; 582 } 583 } 584 } 585 else 586 { 587 if (parent->bf == 0) //情形a* 588 { 589 parent->bf = -1; 590 return root; 591 } 592 else if (parent->bf == 1) //情形b* 593 { 594 parent->bf = 0; 595 if (stackforflashback.empty() == false) 596 { 597 q = parent; 598 parent = stackforflashback.top(); 599 continue; //情形b 600 } 601 else 602 { 603 return root; 604 } 605 } 606 else 607 { 608 p = parent->left; 609 q = parent; 610 if (p->bf == 0) //情形c* 611 { 612 if (stackforflashback.empty() == false) 613 { 614 RotateR(parent);//对以parent为根的子树执行右单旋转 615 if (q == stackforflashback.top()->left) 616 { 617 stackforflashback.top()->left = parent; 618 } 619 else 620 { 621 stackforflashback.top()->right = parent; 622 } 623 } 624 else 625 { 626 RotateR(parent);//对以parent为根的子树执行右单旋转 627 } 628 if (q == root) 629 { 630 return parent; 631 } 632 else 633 { 634 return root; 635 } 636 } 637 else if (p->bf == -1) //情形d* 638 { 639 RotateR(parent);//对以parent为根的子树执行右单旋转 640 } 641 else //情形e* 642 { 643 RotateLR(parent);//对以parent为根的子树执行先左后右双旋转 644 } 645 646 if (stackforflashback.empty() == false) 647 { 648 if (q == stackforflashback.top()->left) 649 { 650 stackforflashback.top()->left = parent; 651 } 652 else 653 { 654 stackforflashback.top()->right = parent; 655 } 656 q = parent; 657 parent = stackforflashback.top(); 658 } 659 else 660 { 661 q = parent; 662 } 663 } 664 } 665 } while (stackforflashback.empty() == false); 666 return q; //原AVL树已恢复平衡,返回根节点 667 } 668 else 669 { 670 cout << "AVL树中不存在要删除的数据元素,删除失败" << endl; 671 return nullptr; 672 } 673 } 674 675 template <typename T> 676 AVLNode<T> *InsertAVL(AVLNode<T> *root, T key) 677 { 678 //AVL树的插入 679 if (root == nullptr) 680 return new AVLNode<T>(0, key); 681 else 682 { 683 stack<AVLNode<T> *> stackforflashback; 684 AVLNode<T> *p = root; 685 while (p != nullptr) //搜索插入位置 686 { 687 stackforflashback.push(p); 688 if (key < p->data) 689 p = p->left; 690 else if (key > p->data) 691 p = p->right; 692 else 693 { 694 cout << "要插入的关键字在AVL树中已存在,插入失败" << endl; 695 return nullptr; 696 } 697 } 698 699 if (key < stackforflashback.top()->data) 700 { 701 stackforflashback.top()->left = new AVLNode<T>(0, key); //新节点插入并调整父节点平衡因子 702 --stackforflashback.top()->bf; 703 } 704 else 705 { 706 stackforflashback.top()->right = new AVLNode<T>(0, key); 707 ++stackforflashback.top()->bf; 708 } 709 710 if (stackforflashback.top()->bf == 0) 711 { 712 return root; //已平衡结束,返回根节点 713 } 714 else 715 { 716 p = stackforflashback.top(); 717 stackforflashback.pop(); 718 if (stackforflashback.empty() == false) 719 { 720 AVLNode<T> *parent = nullptr; 721 while (stackforflashback.empty() == false) 722 { 723 parent = stackforflashback.top(); 724 stackforflashback.pop(); 725 if (parent->left == p) 726 { 727 --parent->bf; 728 if (parent->bf == 0) 729 { 730 return root;//已平衡,返回根节点 731 } 732 else if(parent->bf == -2) 733 { 734 AVLNode<T> *q = parent; 735 if (p->bf == 1) 736 { 737 RotateLR(parent);//对parent为根的子树执行先左后右双旋转 738 //已平衡 739 } 740 else 741 { 742 RotateR(parent);//对以parent为根子树执行右单旋转 743 //已平衡 744 } 745 746 if (stackforflashback.empty() == false) 747 { 748 if (stackforflashback.top()->left == q) 749 stackforflashback.top()->left = parent; 750 else 751 stackforflashback.top()->right = parent; 752 } 753 754 if (q == root) //返回恢复平衡的AVL树根节点 755 return parent; 756 else 757 return root; 758 } 759 else 760 { 761 p = parent; //以parent为根的子树已平衡其高度加一回溯至父节点 762 } 763 } 764 else 765 { 766 ++parent->bf; 767 if (parent->bf == 0) 768 { 769 //已平衡,返回根节点 770 return root; 771 } 772 else if (parent->bf == 2) 773 { 774 AVLNode<T> *q = parent; 775 if (p->bf == -1) 776 { 777 RotateRL(parent);//对parent为根的子树执行先右后左双旋转 778 //已平衡 779 } 780 else 781 { 782 RotateL(parent);//对以parent为根的子树执行左单旋转 783 //已平衡 784 } 785 786 if (stackforflashback.empty() == false) 787 { 788 if (stackforflashback.top()->left == q) 789 stackforflashback.top()->left = parent; 790 else 791 stackforflashback.top()->right = parent; 792 } 793 if (q == root) //返回恢复平衡的AVL树根节点 794 return parent; 795 else 796 return root; 797 } 798 else 799 { 800 p = parent; //以parent为根的子树已平衡其高度加一回溯至父节点 801 } 802 } 803 } 804 return p; //原AVL树已平衡,返回根节点 805 } 806 else 807 { 808 return p; 809 //原AVL树已平衡,返回根节点,结束 810 } 811 } 812 } 813 } 814 815 template <typename T> 816 int Searchd(AVLNode<T> *ptr, int d) 817 { 818 if (d == 2) 819 return 0; 820 else 821 { 822 if (d == 1) 823 { 824 if (ptr->right == nullptr) 825 return 0; 826 else 827 return 2; 828 } 829 else 830 { 831 if (ptr->left != nullptr) 832 return 1; 833 else 834 { 835 if (ptr->right != nullptr) 836 return 2; 837 else 838 return 0; 839 } 840 } 841 } 842 } 843 844 template <typename T> 845 void output(AVLNode<T> *ptr) //输出以ptr为根的AVL树对应的广义表形式 846 { 847 struct memory 848 { 849 AVLNode<T> *p; 850 int direction; 851 int last; 852 memory(AVLNode<T> *p, int d, int l) :p(p), direction(d), last(l) {} 853 }; 854 int d = 0; 855 AVLNode<T> *const dest = ptr; 856 stack<memory> arrange; 857 while (true) 858 { 859 if (Searchd(ptr, d) == 0) 860 { 861 if (ptr == dest) 862 { 863 if (d == 0) 864 cout <<ptr->data<< "("; 865 else 866 { 867 if (arrange.top().last == 1) 868 cout << ", "; 869 } 870 cout << ")"; 871 break; 872 } 873 else 874 { 875 if (d == 0) 876 { 877 if (arrange.top().last == 0) 878 { 879 if (arrange.top().direction == 1) 880 { 881 cout << ptr->data; 882 arrange.top().last = 1; 883 } 884 else 885 { 886 cout << " ," << ptr->data; 887 arrange.top().last = 2; 888 } 889 } 890 else 891 { 892 cout << ","; 893 cout << ptr->data; 894 arrange.top().last = 2; 895 } 896 } 897 else 898 { 899 if (arrange.top().last ==2) 900 cout << ")"; 901 else 902 { 903 cout << ", )"; 904 } 905 arrange.pop(); 906 } 907 ptr = arrange.top().p; 908 d = arrange.top().direction; 909 } 910 } 911 else 912 { 913 AVLNode<T> *interval = nullptr; 914 if (d == 0) 915 { 916 if (arrange.empty() == false) 917 { 918 if (arrange.top().last == 0) 919 { 920 if (arrange.top().direction == 1) 921 { 922 cout << ptr->data <<"("; 923 arrange.top().last = 1; 924 } 925 else 926 { 927 cout << " ," << ptr->data << "("; 928 arrange.top().last = 2; 929 } 930 } 931 else 932 { 933 cout << ","; 934 cout << ptr->data<<"("; 935 arrange.top().last = 2; 936 } 937 } 938 else 939 { 940 cout << ptr->data << "("; 941 } 942 arrange.push(memory(ptr, Searchd(ptr, d), 0)); 943 if (arrange.top().direction == 1) 944 interval = ptr->left; 945 else 946 interval = ptr->right; 947 } 948 else 949 { 950 arrange.top().direction = 2; 951 interval = ptr->right; 952 } 953 d = 0; 954 ptr = interval; 955 } 956 } 957 } 958 int main() 959 { 960 vector<TYPE> insertvalue{ 13, 5, 3, 2, 1, 4, 10, 8, 7, 6, 9, 11, 12, 16, 14, 15, 18, 17, 20, 19 }; 961 AVLNode<TYPE> *root = nullptr; 962 for (vector<TYPE>::const_iterator p = insertvalue.cbegin(); p != insertvalue.cend(); ++p) 963 { 964 cout << "插入节点" << *p << endl; 965 root = InsertAVL(root, *p); 966 output(root); 967 cout << endl; 968 if (isAVL(root) == true) 969 { 970 cout << "当前树是AVL树"; 971 cout << endl; 972 } 973 else 974 { 975 cerr << "错误当前树不是AVL树!" << endl; 976 exit(0); 977 } 978 } 979 cout << endl; 980 cout << "插入完成后删除前AVL树对应的广义表形式为:" << endl; 981 output(root); 982 cout << endl; 983 cout << endl; 984 for (vector<TYPE>::const_iterator p = insertvalue.cbegin(); p != insertvalue.cend(); ++p) 985 { 986 cout << "删除节点" << *p << endl; 987 root = DelAVL(root, *p); 988 if (root != nullptr) 989 { 990 output(root); 991 cout << endl; 992 if (isAVL(root) == true) 993 { 994 cout << "当前树是AVL树"; 995 cout << endl; 996 } 997 else 998 { 999 cerr << "错误当前树不是AVL树!" << endl; 1000 exit(0); 1001 } 1002 } 1003 else 1004 cout << "NULL"; 1005 cout << endl; 1006 } 1007 return 0; 1008 }
运行结果: