AVL 树是带有平衡条件的二叉搜索树。当它不平衡时重排其节点让其再度保持平衡。
平衡节点(balanced node)或者说平衡因子( balance factor)如果节点是平衡树的节点,即它的两颗子树的高度差不大于1,则该节点是平衡的。
BalanceFactor = height(left-sutree) − height(right-sutree)

AVL树的旋转

在AVL树中,每次插入或删除后,则需要检查每个节点的平衡因子,如果每个节点都满足平衡的条件,则可以完成操作,否则需要使用旋转操作重新平衡树。
1.png
旋转分为两种类型,

  • 单旋转
    • 左旋转(LL旋转)
    • 右旋转(RR旋转)
  • 双旋转
    • 左右旋转(LR旋转)
    • 右左旋转(RL旋转)

分别在下列情况下使用

  • 如果左侧子树的右子树存在不平衡则执行左右旋转
  • 如果左侧子树的左子树存在不平衡则执行右旋转
  • 如果右侧子树的右子树存在不平衡则执行坐旋转
  • 如果右侧子树的左子树存在不平衡则执行右左旋转

左旋转(LL旋转)

当一个节点插入到节点A的右子树的右子树位置时,如果树变的不平衡,则执行左旋转。
left.png

  1. Alogrithm rotateLeft(nodeN) //nodeN 就如上图的A节点
  2. //修正给定的节点nodeN的不平衡,因为在nodeN的右子树节点的右子树位置添加了节点C
  3. //将A的右子树赋值给新的变量nodeC 也就是B节点
  4. nodeC = nodeN->rightChild
  5. //将nodeC的左子树赋值给nodeN的右子树 也就是将 将B的左子树赋值给A的右节点
  6. nodeN.rightChild = nodeC.leftChild
  7. //将nodeN赋值给nodeC的左子树 将B 的左子树设置为A
  8. nodeC->leftChild = nodeN
  9. nodeC返回 也就是 B
  10. return nodeC

右旋转(RR旋转)

将一个节点插入到节点C的左子树的左子树位置时,AVL树可能变的不平衡,此时需要右旋转
right.png

  1. Alogrithm rotateRight(nodeN) //nodeN 就如上图的C节点
  2. //修正给定的节点nodeN的不平衡,因为在nodeN的左子树节点的右子树位置添加了节点A
  3. //将C的左子树赋值给新的变量nodeC 也就是B节点
  4. nodeC = nodeN->leftChild
  5. //将nodeC的右子树赋值给nodeN的左子树 也就是将 将B的右子树赋值给C的左子树
  6. nodeN.leftChild = nodeC.rightChild
  7. //将nodeN赋值给nodeC的右子树 将B 的右子树设置为C节点
  8. nodeC->rightChild = nodeN
  9. nodeC返回 也就是 B
  10. return nodeC

左右旋转(LR旋转)

如果在节点C左子树节点的右子树位置插入节点时,树变的不平衡,则执行左右旋转。左右旋转顾明思义,先左旋转再右旋转
left-right.png

  1. Alogrithm rotateLeftRight(nodeN) nodeN代表上图中的C
  2. //修正给定的节点nodeN的不平衡,因为在nodeNd的左子树节点的右子树位置插入了新节点 B
  3. //将nodeN(C)节点左子树 赋值给一个新的辅助变量nodeC (等于节点A)
  4. nodeC = nodeN->leftChild
  5. //对节点A 进行左旋转,并将返回值赋值给nodeN(C)节点的左子树
  6. nodeN->leftChild = rotateLeft(nodeC);
  7. //再对节点nodeN(C)进行右旋转
  8. return rotateRight(nodeN)

右左旋转(RL旋转)

如果在节点A的右子树的左子树位置插入节点时,树变的不平衡,则执行右左旋转。就是先右旋转再左旋转
right-left.png

  1. Alogrithm rotateRightLeft(nodeN) nodeN代表上图中的A
  2. //修正给定的节点nodeN的不平衡,因为在nodeNd的右子树节点的左子树位置插入了新节点 B
  3. //将nodeN(A)节点的右子树 赋值给一个新的辅助变量nodeC (等于节点C)
  4. nodeC = nodeN->rightChild
  5. //对节点C 进行右旋转,并将返回值赋值给nodeN(A)节点的右子树
  6. nodeN->rightChild = rotateRight(nodeC);
  7. //再对节点nodeN(A)进行左旋转
  8. return rotateRLeft(nodeN)

再平衡算法

  1. Alogrithm rebalance(nodeN)
  2. if(nodeN的左子树的高度与其右子树的高度查大于1)
  3. {
  4. // 在nodeN的左子树中添加
  5. if(nodeN的左孩子的左子树高于其右子树){
  6. rotateRight(nodeN) //在左孩子的左子树中添加
  7. }else {
  8. rotateLeftRight(nodeN) // 在左孩子的右子树中添加
  9. }
  10. }else if(nodeN的右子树的高度与其左子树的高度差大于1){
  11. if(nodeN的右孩子的右子树比其左子树高)
  12. {
  13. rotateLeft(nodeN) // 在右孩子的右子树中添加
  14. }else {
  15. rotateRightLeft(nodeN) // 在右孩子的左子树中添加
  16. }
  17. }
  1. #ifndef AVL_TREE_H
  2. #define AVL_TREE_H
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <math.h>
  6. #include <assert.h>
  7. struct AVLNode;
  8. typedef struct AVLNode *AvlNode;
  9. typedef struct AVLNode *AVLTree;
  10. // 创建节点
  11. AVLTree createAvlNode(const int data);
  12. // 查找指定数据的节点
  13. AvlNode find(const int data, const AVLTree tree);
  14. // 查找最小节点
  15. AvlNode findMin(const AVLTree tree);
  16. // 查找最大节点
  17. AvlNode findMax(const AVLTree tree);
  18. // 插入数据
  19. AVLTree insert(const int data, AVLTree tree);
  20. // 删除
  21. AVLTree deleteNode(const int data, AVLTree tree);
  22. // 旋转
  23. // 左旋转(LL旋转)
  24. AVLTree rotateLeft(AVLTree node);
  25. // 右旋转(RR旋转)
  26. AVLTree rotateRight(AVLTree node);
  27. // 右左旋转(RL旋转)
  28. AVLTree rotateRightLeft(AVLTree node);
  29. // 左右旋转(LR旋转)
  30. AVLTree rotateLeftRight(AVLTree node);
  31. // 再平衡 通过旋转让AVL 树再度平衡
  32. AVLTree rebalance(const int data, AVLTree node);
  33. // 节点 struct
  34. struct AVLNode
  35. {
  36. /* data */
  37. int data;
  38. int height;
  39. AVLTree left;
  40. AVLTree right;
  41. };
  42. AVLTree createAvlNode(const int data)
  43. {
  44. AVLTree node = (AVLTree)malloc(sizeof(AVLTree));
  45. if (node == NULL)
  46. {
  47. printf("createAvlNode 内存分配出错!\n");
  48. exit(EXIT_FAILURE);
  49. }
  50. node->data = data;
  51. node->left = node->right = NULL;
  52. node->height = 0;
  53. return node;
  54. };
  55. // 获取avl树的高度
  56. static int height(AvlNode node)
  57. {
  58. if (node == NULL)
  59. return -1;
  60. return node->height;
  61. }
  62. static int maxNumber(const int a, const int b)
  63. {
  64. return a > b ? a : b;
  65. };
  66. static int getMaxHeight(AVLTree node)
  67. {
  68. return maxNumber(height(node->left), height(node->right)) + 1;
  69. }
  70. // 递归查找左节点 为最小
  71. AVLTree findMin(AVLTree tree)
  72. {
  73. if (tree == NULL)
  74. return NULL;
  75. if (tree->left == NULL)
  76. return tree;
  77. return findMin(tree->left);
  78. }
  79. // 循环查找右节点 为最大
  80. AVLTree findMax(AVLTree tree)
  81. {
  82. if (tree != NULL)
  83. {
  84. while (tree->right != NULL)
  85. {
  86. tree = tree->right;
  87. }
  88. }
  89. return tree;
  90. }
  91. // 左旋转(LL旋转)
  92. AVLTree rotateLeft(AVLTree node)
  93. {
  94. // 拿出右子树节点
  95. AVLTree rightNode = node->right;
  96. assert(rightNode != NULL);
  97. // 将右子树的左子树赋值给当前旋转节点的有右节点
  98. node->right = rightNode->left;
  99. //将 当前旋转节点赋值给右子树的左节点
  100. rightNode->left = node;
  101. // 重新设置高度
  102. node->height = getMaxHeight(node);
  103. rightNode->height = getMaxHeight(rightNode);
  104. //完成旋转 将右子树返回
  105. return rightNode;
  106. }
  107. // 右旋转(RR旋转)
  108. AVLTree rotateRight(AVLTree node)
  109. { // 拿出左子树节点
  110. AVLTree leftNode = node->left;
  111. assert(leftNode != NULL);
  112. // 将左子树的右子树节点赋值给当前旋转节点的左侧节点
  113. node->left = leftNode->right;
  114. // 将当前旋转节点赋值给左子树的右侧节点
  115. leftNode->right = node;
  116. // 重新设置高度
  117. node->height = getMaxHeight(node);
  118. leftNode->height = getMaxHeight(leftNode);
  119. // 完成旋转 将左子树节点返回
  120. return leftNode;
  121. };
  122. // 左右旋转(LR旋转)
  123. AVLTree rotateLeftRight(AVLTree node)
  124. {
  125. assert(node != NULL && node->left != NULL);
  126. // 先对当前旋转节点的左子树节点进行左旋转 并将返回值赋值给左子树
  127. node->left = rotateLeft(node->left);
  128. // 再对当前旋转节点进行右旋转
  129. return rotateRight(node);
  130. }
  131. // 右左旋转(RL旋转)
  132. AVLTree rotateRightLeft(AVLTree node)
  133. {
  134. assert(node != NULL && node->right != NULL);
  135. // 先对当前旋转节点的右子树节点进行右旋转 并将返回值赋值给右子树
  136. node->right = rotateRight(node->right);
  137. // 再对当前旋转节点进行左旋转
  138. return rotateLeft(node);
  139. }
  140. // 再平衡 通过旋转让AVL 树再度平衡
  141. AVLTree rebalance(const int data, AVLTree node)
  142. {
  143. if (node == NULL)
  144. return NULL;
  145. // 两颗子树的高度差不大于1,则该节点是平衡的
  146. // 左子树的高度大于右子树的高度 并且差值大于1 节点不平衡
  147. if (height(node->left) - height(node->right) > 1)
  148. {
  149. // 当前插入的值小于 左子树的值 说明 这个新节点插入到了左子树的左子树节点的位置 进行右旋转
  150. if (data < node->left->data)
  151. {
  152. node = rotateRight(node);
  153. }
  154. else // 否则就是插入了 左子树的右子树节点位置 进行左右旋转
  155. {
  156. node = rotateLeftRight(node);
  157. }
  158. }
  159. // 右子树的高度大于左子树的高度 并且差值大于1 节点不平衡
  160. else if (height(node->right) - height(node->left) > 1)
  161. {
  162. // 当前插入的值大于 右子树的值 说明 这个新节点插入到了 右子树的右子树的位置 进行左旋转
  163. if (data > node->right->data)
  164. {
  165. node = rotateLeft(node);
  166. }
  167. else // 否则就是在右子树的左子树位置 进行右左旋转
  168. {
  169. node = rotateRightLeft(node);
  170. }
  171. }
  172. return node;
  173. };
  174. AVLTree insert(const int data, AVLTree tree)
  175. {
  176. if (tree == NULL)
  177. {
  178. tree = createAvlNode(data);
  179. }
  180. else if (data < tree->data)
  181. { //比当前节点小 插入左子树中
  182. tree->left = insert(data, tree->left);
  183. }
  184. else if (data > tree->data)
  185. {
  186. // 比当前节点的值大,插入右子树中
  187. tree->right = insert(data, tree->right);
  188. }
  189. // 再平衡
  190. tree = rebalance(data, tree);
  191. tree->height = getMaxHeight(tree);
  192. return tree;
  193. }
  194. // 删除节点
  195. AVLTree deleteNode(const int data, AVLTree tree)
  196. {
  197. if (tree == NULL)
  198. return NULL;
  199. if (tree->data > data)
  200. {
  201. // 小于当前节点值 去左子树节点查找
  202. tree->left = deleteNode(data, tree->left);
  203. }
  204. else if (tree->data < data)
  205. {
  206. // 大于当前节点值 右去子树节点查找
  207. tree->right = deleteNode(data, tree->right);
  208. }
  209. else if (tree->left && tree->right)
  210. {
  211. // 找到右子树最小的节点,替换当前节点
  212. AVLTree temp = findMin(tree->right);
  213. tree->data = temp->data;
  214. // 再将最小节点删除
  215. tree->right = deleteNode(temp->data, tree->right);
  216. }
  217. else
  218. {
  219. AVLTree temp = tree;
  220. if (tree->left == NULL)
  221. {
  222. tree = tree->right;
  223. }
  224. else if (tree->right == NULL)
  225. {
  226. tree = tree->left;
  227. }
  228. free(temp);
  229. }
  230. // 再平衡
  231. tree = rebalance(data, tree);
  232. return tree;
  233. };
  234. void printTree(AVLTree tree, int level)
  235. {
  236. if (tree != NULL)
  237. {
  238. printTree(tree->left, level + 1);
  239. printf("node data = %d, height = %d , level = %d\n", tree->data, tree->height, level);
  240. printTree(tree->right, level + 1);
  241. }
  242. }
  243. #endif //AVL_TREE_H

AVL树的插入和删除

avl树的插入和删除是与二叉搜索树一致的,不同的是在插入或者删除节点之后,调用 rebalance 函数判断是否需要进行旋转再平衡。