• C++之AVL树详解


    首先我们需要了解一下AVL树概念:
           二叉树虽然可以提高搜索的效率,但是当数据有序接近有序二叉树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下,因此便有人提出了AVL树的概念,当向二叉树插入新的节点后,如果可以保证每个节点的左右子树高度之差得到绝对值不超过1,即可降低树的高度,从而减少平均搜索长度

    接下来我们就来简易搭建一下构架:

    1. template<class K,class V>
    2. struct AVLTreeNode
    3. {
    4. AVLTreeNode*_left;
    5. AVLTreeNode*_right;
    6. AVLTreeNode*_parent;
    7. pair _kv;
    8. int _bf;
    9. AVLTreeNode(const pair&kv)
    10. :_left(nullptr)
    11. ,_right(nullptr)
    12. ,_parent(nullptr)
    13. ,_kv(kv)
    14. ,_bf(0)
    15. {}
    16. }
    17. template<class K,class V>
    18. {
    19. typedef AVLTreeNodeM Node;
    20. public:
    21. bool Insert(const pair& kv)
    22. {
    23. if(_root==nullptr)
    24. {
    25. _root=new Node(kv);
    26. return true;
    27. }
    28. Node* parent=nullptr;
    29. Node* cur=_root;
    30. while(cur)
    31. {
    32. if(cur->_kv.first
    33. {
    34. parent=cur;
    35. cur=cur->_right;
    36. }
    37. else if(cur->_kv.first>kv.first)
    38. {
    39. parent=cur;
    40. cur=cur->_left;
    41. }
    42. else//二者相同的情况
    43. {
    44. return false;
    45. }
    46. }
    47. cur=new Node(kv);
    48. if(parent->_kv.first
    49. {
    50. parent->_right=cur;
    51. }
    52. else if(parnet->kv.first>kv.first)
    53. {
    54. parent->_left=cur;
    55. }
    56. cur->_parent=parent;
    57. return true;
    58. }
    59. private:
    60. Node* _root=nullptr;
    61. }

    这里我们bf设置为0即可,接下来我么就来对平衡因子进行编写:

    更新平衡因子的规则:
    (1)新增在右,parent->bf++;新增在左,parent->bf--;

    (2)更新后,parent->bf==1 or -1,说明parent之前是0,(注意:在这里parent之前一定不是2或者-2,否则之前就是不平衡的),说明左右子树高度相同,插入后有一边高,parent的高度变了,需要继续往上更新

    (3)更新后,parent->bf==0,说明此时就不需要继续往上更新

    (4)如果更新后,parent->bt==2或者-2,说明说明原来就是1或者-1,已经是平衡的临界值

    1. template<class K,class V>
    2. struct AVLTreeNode
    3. {
    4. AVLTreeNode*_left;
    5. AVLTreeNode*_right;
    6. AVLTreeNode*_parent;
    7. pair _kv;
    8. int _bf;
    9. AVLTreeNode(const pair&kv)
    10. :_left(nullptr)
    11. ,_right(nullptr)
    12. ,_parent(nullptr)
    13. ,_kv(kv)
    14. ,_bf(0)
    15. {}
    16. }
    17. template<class K,class V>
    18. {
    19. typedef AVLTreeNodeM Node;
    20. public:
    21. bool Insert(const pair& kv)
    22. {
    23. if(_root==nullptr)
    24. {
    25. _root=new Node(kv);
    26. return true;
    27. }
    28. Node* parent=nullptr;
    29. Node* cur=_root;
    30. while(cur)
    31. {
    32. if(cur->_kv.first
    33. {
    34. parent=cur;
    35. cur=cur->_right;
    36. }
    37. else if(cur->_kv.first>kv.first)
    38. {
    39. parent=cur;
    40. cur=cur->_left;
    41. }
    42. else//二者相同的情况
    43. {
    44. return false;
    45. }
    46. }
    47. cur=new Node(kv);
    48. if(parent->_kv.first
    49. {
    50. parent->_right=cur;
    51. }
    52. else if(parnet->kv.first>kv.first)
    53. {
    54. parent->_left=cur;
    55. }
    56. cur->_parent=parent;
    57. //平衡因子编写
    58. while(parent)
    59. {
    60. if(cut==parent->_right)
    61. {
    62. parent->_bf++;
    63. }
    64. else
    65. {
    66. parent->_bf--;
    67. }
    68. if(parent->_bf==0)
    69. {
    70. break;
    71. }
    72. if(abs(parent>_bf)==1)
    73. {
    74. parent=parent->_parent;
    75. cur=cur->_parent;
    76. }
    77. else if(abs(parent->_bf)==2)
    78. {
    79. //说明parent的子树已经不平衡了,需要旋转处理
    80. }
    81. else
    82. {
    83. assert(false);//理论上是不会到这里的
    84. }
    85. }
    86. return true;
    87. }
    88. private:
    89. Node* _root=nullptr;
    90. }

     接下来我们一起来了解一下旋转机制:
    首先原则就是:

    (1)旋转为平衡树

    (2)保持搜索树原则

    接下来我们就逐个讲解一下各个旋转规则:、


    一.左单旋:
     

    首先我们要知道为什么要叫做左旋转,其实根本就是右边高了,导致平衡因子变大,具体图如下:

     最右边的子树加1,此时60的平衡因子就变作1,30就变作2,此时就需要旋转。具体调节方法如上图;

    其实也就是只要最右边加成员,就会发生左旋:

    一.左旋

    1. template<class K,class V>
    2. struct AVLTreeNode
    3. {
    4. AVLTreeNode*_left;
    5. AVLTreeNode*_right;
    6. AVLTreeNode*_parent;
    7. pair _kv;
    8. int _bf;
    9. AVLTreeNode(const pair&kv)
    10. :_left(nullptr)
    11. ,_right(nullptr)
    12. ,_parent(nullptr)
    13. ,_kv(kv)
    14. ,_bf(0)
    15. {}
    16. }
    17. template<class K,class V>
    18. {
    19. typedef AVLTreeNodeM Node;
    20. public:
    21. bool Insert(const pair& kv)
    22. {
    23. if(_root==nullptr)
    24. {
    25. _root=new Node(kv);
    26. return true;
    27. }
    28. Node* parent=nullptr;
    29. Node* cur=_root;
    30. while(cur)
    31. {
    32. if(cur->_kv.first
    33. {
    34. parent=cur;
    35. cur=cur->_right;
    36. }
    37. else if(cur->_kv.first>kv.first)
    38. {
    39. parent=cur;
    40. cur=cur->_left;
    41. }
    42. else//二者相同的情况
    43. {
    44. return false;
    45. }
    46. }
    47. cur=new Node(kv);
    48. if(parent->_kv.first
    49. {
    50. parent->_right=cur;
    51. }
    52. else if(parnet->kv.first>kv.first)
    53. {
    54. parent->_left=cur;
    55. }
    56. cur->_parent=parent;
    57. //平衡因子编写
    58. while(parent)
    59. {
    60. if(cut==parent->_right)
    61. {
    62. parent->_bf++;
    63. }
    64. else
    65. {
    66. parent->_bf--;
    67. }
    68. if(parent->_bf==0)
    69. {
    70. break;
    71. }
    72. if(abs(parent>_bf)==1)
    73. {
    74. parent=parent->_parent;
    75. cur=cur->_parent;
    76. }
    77. else if(abs(parent->_bf)==2)
    78. {
    79. //说明parent的子树已经不平衡了,需要旋转处理
    80. if(parent->_bf==2 &&cur->bf==0)
    81. {
    82. Rotatel(parent);
    83. }
    84. break;
    85. }
    86. else
    87. {
    88. assert(false);//理论上是不会到这里的
    89. }
    90. }
    91. return true;
    92. }
    93. private:
    94. void Rotatel(Node* parent)
    95. {
    96. Node* subR=parent->_right;
    97. Node* suRL=subR->_left;
    98. parent->_right=subRL;
    99. if(subPL)
    100. {
    101. subRL->_parent=parent;
    102. }
    103. Node* ppNode=parent->_parent;
    104. subR->_left=parent;
    105. parent->_parent=subR;
    106. if(parent==_root)//如果父母就是根
    107. {
    108. _root=subR;
    109. subR->_parent=nullptr;
    110. }
    111. else//如果父母不是根,而是子树
    112. {
    113. if(ppNode->_left=parent)
    114. {
    115. ppNode->_left=subR;
    116. }
    117. else
    118. {
    119. ppNode->_right=subR;
    120. }
    121. subR->_parent=ppNode;
    122. }
    123. subR->_bf=parent->_bf=0;
    124. }
    125. private:
    126. Node* _root=nullptr;
    127. }

    二.右旋

    具体图如下: 

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

    前提条件如下:

    1. if((parent->_bf==-2) && (cur->_bf==-1))
    2. {
    3. RotateR(parent);
    4. }

    三.双旋

    (1)左右双旋

     

    1. void RotateLR(Node* parent)
    2. {
    3. Node* subL=parent->_left;
    4. Node* subLR=subL->_right;
    5. int bf=subLR->_bf;
    6. RotateL(parent->_left);
    7. RotateR(parent);
    8. subLR->_bf=0;
    9. if(bf==1)
    10. {
    11. parent->_bf=0;
    12. subL->_bf=-1;
    13. }
    14. else if(bf==-1)
    15. {
    16. parent->_bf=1;
    17. subL->_bf=0;
    18. }
    19. else if(bf==0)
    20. {
    21. parent->_bf=0;
    22. subL->_bf=0;
    23. }
    24. else
    25. {
    26. assert(false);
    27. }
    28. }

    (2)右左双旋

    1. void RotateRL(Node* parent)
    2. {
    3. Node* subR=parent->_right;
    4. Node* subRL=subR->_left;
    5. int bf=subRL->_bf;
    6. RotateR(parent->_left);
    7. RotateL(parent);
    8. if(bf==1)
    9. {
    10. subR->_bf=0;
    11. parent->_bf=-1;
    12. subRL->_bf=0;
    13. }
    14. else if(bf==-1)
    15. {
    16. subR->_bf=1;
    17. parent->_bf=0;
    18. subRL->_bf=0;
    19. }
    20. else if(bf==0)
    21. {
    22. parent->_bf=0;
    23. subR->_bf=0;
    24. }
    25. else
    26. {
    27. assert(false);
    28. }
    29. }

    最后我们来了解一下旋转的价值与意义:
    1.使当前这棵树平衡

    2.降低树的高度

    以上就是文章所有内容,希望对您有帮助!

  • 相关阅读:
    深度学习的数值问题
    使用c#的 async/await编写 长时间运行的基于代码的工作流的 持久任务框架
    华为手机的10个使用技巧,你知道吗
    并查集的实现的应用
    java基于ssm+vue的考研信息查询系统 elementui
    如何安装TortoiseSVN并实现公网提交文件至本地SVN服务器?
    java数据库linux面试(详细)
    Kali Linux渗透测试高级篇 1-1 OSINT介绍
    Python 学习 第二册 第14章 网络编程
    漫谈:C语言 C++ 迷惑的语句、分号、大括号
  • 原文地址:https://blog.csdn.net/weixin_64394633/article/details/127694766