• 波奇学C++:AVL树


    AVL解决二叉搜索树退化成链表,保证左右子树高度不差过1,尽可能接近满二叉树

    AVL树的性质:高度差(平衡因子)的绝对值不超过1(-1/0/1)

    平衡因子:右子树高度-左子树高度

    用平衡因子控制高度

    AVL树节点

    1. class AVLTreeNode
    2. {
    3. pair_kv; //key/value
    4. AVLTreeNode* _left; // 左
    5. AVLTreeNode* _right;// 右
    6. AVLTreeNode* _partent;// 父母
    7. int _bf;// 平衡因子
    8. AVLTreeNode(const pair& kv)
    9. :_kv(kv)
    10. ,_left(nullptr)
    11. ,_right(nullptr)
    12. ,_parent(nullptr)
    13. ,_bf(0)
    14. {}
    15. };

     控制逻辑:增加一个新节点cur

     parent的bf值-1,在右 ,parent的bf加1

    如果parent_bf=0,则不再改变,否则继续向上调整,直到parent为0,或者为cur为根节点时。

    如果parent的平衡因子为2或者-2,说明树不平衡,要进行旋转调整。

    当左边高时(parent=2,cur=1)

    柱子a,b,c表示高度为h的AVL树

    1. parent->right=cur->left
    2. cur->left=parent

    对于左单旋的理解:1.根节点向左转,2.c树高度增加后a树高2,于是把c的父节点当成根节点使得c的高度方向-1,a的树的方向+1,刚好平衡

    同时调整平衡因子数量和parent指针

    左单旋

    1. void RotateL(Node* parent)
    2. {
    3. Node* cur = parent->_right; //确定cur
    4. Node* curleft = parent->_left;
    5. parent->_left = curleft;
    6. //当h不为0时
    7. if (curleft)
    8. {
    9. //调整parent指针
    10. curleft->_partent = parent;
    11. }
    12. cur->_left = parent;
    13. //调整新的根节点的parent指针
    14. Node* ppnode = parent->_parent;
    15. parent->_parent = cur;
    16. //根节点特殊情况
    17. if (parent == _root)
    18. {
    19. _root = cur;
    20. cur->_partent = nullptr;
    21. }
    22. else
    23. {
    24. // 确定parent是ppnode的左指针还是右指针
    25. if (ppnode->_left==parent)
    26. {
    27. ppnode->_left = cur;
    28. }
    29. else
    30. {
    31. ppnode_right = cur;
    32. }
    33. cur->_partent = ppnode;
    34. }
    35. parent->_bf = cur->_bf = 0;
    36. }

     

     

    1. void RotateR()
    2. {
    3. void RotateR(Node* parent)
    4. {
    5. Node* cur = parent->_left;
    6. Node* curright = cur->_right;
    7. parent->_left = curright;
    8. cur->_right = parent;
    9. Node* ppnode = parent->_parent;
    10. if (curright)
    11. {
    12. curright->_partent = parent;
    13. }
    14. parent->_parent = cur;
    15. if (ppnode == root)
    16. {
    17. _root = cur;
    18. cur->_partent = nullptr;
    19. }
    20. else
    21. {
    22. if (ppnode->_left == parent)
    23. {
    24. ppnode->_left = cur;
    25. }
    26. else(ppnode->_right == parent)
    27. {
    28. ppnode->_right = cur;
    29. }
    30. }
    31. cur->_bf = parent->_bf = 0;
    32. }
    33. }

     双旋:我们发现左右双旋都是在都是a,c树高度发生变化,具体体现在cur和parent的平衡因子都是相差1,而如果在b树发生变化,无论是左边高还是右边高都会产生双旋问题。具体可以分为四种情况,现在以一种情况为例:

    如下图是右边高的b树(现为60-b-c子树)发生改变。

     从图上来讲是90进行右旋,把高的树的树移到外面,再30进行左旋,构建平衡。
     

     

    对于父节点为60的树来说,左树成为30节点的右树,右树成为90节点的左树。

    所以60的节点的双旋后30,60,90的_bf值不恒为0,30,90节点会受到60的影响。

    当60->_bf=1, 30,60,90 =-1 ,0,0

    60->_bf=-1, 30,60,90 = 1,0,0

    左高右高的区别都是60做根节点,且_bf变化是一样的。

    左高:先左旋后右旋,右高,先右旋后左旋。

    插入代码和旋转代码

    1. bool Insert(const pair& kv)
    2. {
    3. if (_root == nullptr)
    4. {
    5. _root = new Node(kv);
    6. return true;
    7. }
    8. Node* parent = nullptr;
    9. Node* cur = _root;
    10. while (cur)
    11. {
    12. if (cur->_kv.first < kv.first)
    13. {
    14. parent = cur;
    15. cur = cur->_right;
    16. }
    17. else if (cur->_kv.first > kv.first)
    18. {
    19. parent = cur;
    20. cur = cur->_left;
    21. }
    22. else
    23. {
    24. return false;
    25. }
    26. }
    27. cur = new Node(kv);
    28. if (parent->_kv.first < kv.first)
    29. {
    30. parent->_right = cur;
    31. }
    32. else if (parent->_kv.first > kv.first)
    33. {
    34. parent->_left = cur;
    35. }
    36. cur->_parent = parent;
    37. return true;
    38. // 更新节点
    39. while (parent)
    40. {
    41. if (cur == parent->_left)
    42. {
    43. parent->_bf--;
    44. }
    45. else
    46. {
    47. parent->_bf++;
    48. }
    49. if (parent->_bf == 0)
    50. {
    51. break;
    52. }
    53. else if (parent->_bf == 1 || parent->_bf == -1)
    54. {
    55. cur = parent;
    56. parent = parent->_parent;
    57. }
    58. else if (parent->_bf == 2 || parent->_bf == -2)
    59. {
    60. if (parent->_bf == 2 && cur->_bf == 1)
    61. {
    62. RotateL(parent);
    63. }
    64. else if (parent->_bf == -2 && cur->_bf == -1)
    65. {
    66. RotateR(parent);
    67. }
    68. else if (parent->_bf == 2 && cur->_bf == -1)
    69. {
    70. //右高双旋
    71. RotateRL(parent);
    72. }
    73. else
    74. {
    75. //左高双旋
    76. RotateLR(parent);
    77. }
    78. }
    79. else
    80. {
    81. assert(false);
    82. }
    83. }
    84. return true;
    85. }
    86. void RotateL(Node* parent)
    87. {
    88. Node* cur = parent->_right;
    89. Node* curleft = parent->_left;
    90. parent->_left = curleft;
    91. if (curleft)
    92. {
    93. curleft->_parent = parent;
    94. }
    95. cur->_left = parent;
    96. Node* ppnode = parent->_parent;
    97. parent->_parent = cur;
    98. if (parent == _root)
    99. {
    100. _root = cur;
    101. cur->_parent = nullptr;
    102. }
    103. else
    104. {
    105. if (ppnode->_left==parent)
    106. {
    107. ppnode->_left = cur;
    108. }
    109. else
    110. {
    111. ppnode->_right = cur;
    112. }
    113. cur->_parent = ppnode;
    114. }
    115. parent->_bf = cur->_bf = 0;
    116. } void RotateR(Node* parent)
    117. {
    118. Node* cur = parent->_left;
    119. Node* curright = cur->_right;
    120. parent->_left = curright;
    121. cur->_right = parent;
    122. Node* ppnode = parent->_parent;
    123. if (curright)
    124. {
    125. curright->_parent = parent;
    126. }
    127. parent->_parent = cur;
    128. if (ppnode == _root)
    129. {
    130. _root = cur;
    131. cur->_parent = nullptr;
    132. }
    133. else
    134. {
    135. if (ppnode->_left == parent)
    136. {
    137. ppnode->_left = cur;
    138. }
    139. else
    140. {
    141. ppnode->_right = cur;
    142. }
    143. }
    144. cur->_bf = parent->_bf = 0;
    145. }
    146. //右高先右后左
    147. void RotateRL(Node* parent)
    148. {
    149. Node* cur = parent->_right;
    150. Node* curleft = cur->_left;
    151. int bf = curleft->_bf;
    152. RotateR(parent->_right);
    153. RotateL(parent);
    154. if (bf == 1)
    155. {
    156. cur->_right->_bf = 0;
    157. cur->_left->_bf= -1;
    158. }
    159. else if (bf == -1)
    160. {
    161. cur->_right->_bf = 0;
    162. cur->_left->_bf = 1;
    163. }
    164. else
    165. {
    166. ;
    167. }
    168. }
    169. void RotateLR(Node* parent)
    170. {
    171. Node* cur = parent->_left;
    172. Node* curright = cur->_right;
    173. int bf = curright->_bf;
    174. RotateL(cur);
    175. RotateR(parent);
    176. if(bf == 1)
    177. {
    178. cur->_right->_bf = 0;
    179. cur->_left->_bf = -1;
    180. }
    181. else if(bf==-1)
    182. {
    183. cur->_right->_bf = 0;
    184. cur->_left->_bf = 1;
    185. }
    186. else
    187. {
    188. ;
    189. }
    190. }

    检验AVL树

    1. int Height(Node* root)
    2. {
    3. if (root == nullptr)
    4. return true;
    5. int leftHight = Height(root->_left);
    6. int right = Height(root->_right);
    7. return leftHeight > rightHeight ? leftHeight + 1 : rightHeigth + 1;
    8. }
    9. bool IsBalance(Node* root)
    10. {
    11. if (root == nullptr)
    12. return true;
    13. int leftHight = Height(root->_left);
    14. int rightHight = Height(root->_right);
    15. if (rightHight-leftHight!=root->_bf)
    16. {
    17. cout<<"平衡因子异常"
    18. }
    19. return abs(rightHight - leftHight) < 2
    20. && IsBalance(root->_left)
    21. && IsBalance(root->_right);
    22. }

  • 相关阅读:
    (一)JVM实战——jvm的组成部分详解
    解析java中的String类中的常用方法(三)
    Node.js项目(二)
    java分割大文件为多个小文件
    【牛客网-公司真题-前端入门篇】——奇安信春招笔试-前端-卷2
    我终于读懂了设计模式的七大原则。。。
    第9周 基于MinIO与OSS实现分布式与云存储
    常用损失函数详解:广泛使用的优化约束方法
    SSH远程登录协议
    机器学习(二)什么是机器学习
  • 原文地址:https://blog.csdn.net/Bagayalu1234567/article/details/133558646