• C++简单实现AVL树


    目录

    一、AVL树的概念

    二、AVL树的性质

    三、AVL树节点的定义

    四、AVL树的插入

    4.1 parent的平衡因子为0

    4.2 parent的平衡因子为1或-1

    4.3 parent的平衡因子为2或-2

    4.3.1 左单旋

    4.3.2 右单旋

    4.3.3 先左单旋再右单旋

    4.3.4 先右单旋再左单旋

    4.4 插入节点完整代码:

    五、AVL树判断是否平衡

    六、AVL树的验证


    一、AVL树的概念

    二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查
    找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii
    和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

    二、AVL树的性质

    1、空树也是一颗AVL树

    2、它的左右子树都是AVL树

    3、左右子树高度差(平衡因子)的绝对值不超过1

    4、如果一颗二叉搜索树是高度平衡的,它就是AVL树。如果它由N个节点,其高度可保持在O(log2N),搜索时间复杂度为O(log2N)。

    三、AVL树节点的定义

    1. template<class K, class V>
    2. struct AVLTreeNode
    3. {
    4. AVLTreeNode(const pair& kv)
    5. :_kv(kv)
    6. ,_parent(nullptr)
    7. ,_left(nullptr)
    8. ,_right(nullptr)
    9. ,_bf(0)//平衡因子初始为0
    10. {}
    11. pair _kv;
    12. AVLTreeNode* _parent;
    13. AVLTreeNode* _left;
    14. AVLTreeNode* _right;
    15. int _bf;//平衡因子 —— balance factor
    16. };

    四、AVL树的插入

    AVL树的插入分为两大步:

    1、新建节点,插入到正确的位置(使之符合二叉搜索树的性质)

    如果插入到右边,则平衡因子加1,如果插入到左边,平衡因子减1;

    2、判断平衡因子是否合法,不合法则调整节点(旋转)

    插入完成后平衡因子有以下几种情况:

    4.1 parent的平衡因子为0

    如果此时parent的平衡因子为0,那么之前的平衡因子是1或-1,这棵树的高度不会变,不用向上更新,插入完成。

    4.2 parent的平衡因子为1或-1

    如果此时parent的平衡因子为1或-1,那么之前的平衡因子为0,高度改变了,需要向上更新。

    4.3 parent的平衡因子为2或-2

    如果此时parent的平衡因子为2或-2,那么需要通过旋转调平衡。

    4.3.1 左单旋

    1. void RotateL(Node* parent)
    2. {
    3. Node* cur = parent->_right;
    4. Node* curleft = cur->_left;
    5. parent->_right = curleft;
    6. cur->_left = parent;
    7. if (curleft)
    8. curleft->_parent = parent;
    9. Node* ppnode = parent->_parent;
    10. parent->_parent = cur;
    11. if (parent == _root)
    12. {
    13. cur->_parent = nullptr;
    14. _root = cur;
    15. }
    16. else
    17. {
    18. if (ppnode->_left == parent)
    19. {
    20. ppnode->_left = cur;
    21. }
    22. else
    23. {
    24. ppnode->_right = cur;
    25. }
    26. cur->_parent = ppnode;
    27. }
    28. parent->_bf = cur->_bf = 0;//更新平衡因子
    29. }

    4.3.2 右单旋

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

    4.3.3 先左单旋再右单旋

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

    4.3.4 先右单旋再左单旋

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

    4.4 插入节点完整代码:

    1. bool insert(const pair& kv)
    2. {
    3. //如果root为空
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(kv);
    7. return true;
    8. }
    9. //插入
    10. Node* cur = _root;
    11. Node* parent = cur;
    12. while (cur)
    13. {
    14. if (cur->_kv.first < kv.first)
    15. {
    16. parent = cur;
    17. cur = cur->_right;
    18. }
    19. else if (cur->_kv.first > kv.first)
    20. {
    21. parent = cur;
    22. cur = cur->_left;
    23. }
    24. else
    25. {
    26. return false;
    27. }
    28. }
    29. cur = new Node(kv);
    30. if (parent->_kv.first < kv.first)
    31. {
    32. parent->_right = cur;
    33. }
    34. else
    35. {
    36. parent->_left = cur;
    37. }
    38. cur->_parent = parent;//刚开始忘记写了
    39. //插入完成,开始判断是否平衡
    40. //最坏走到根就不再判断了,根的parent为空
    41. while (parent)
    42. {
    43. //更新平衡因子
    44. if (parent->_left == cur)
    45. {
    46. parent->_bf--;
    47. }
    48. else
    49. {
    50. parent->_bf++;
    51. }
    52. //如果此时parent的平衡因子为0,那么之前的平衡因子是1或-1,这棵树的高度不会变,不用向上更新
    53. if (parent->_bf == 0)
    54. {
    55. break;
    56. }
    57. //如果此时parent的平衡因子为1或-1,那么之前的平衡因子为0,高度改变了,需要向上更新
    58. else if (parent->_bf == 1 || parent->_bf == -1)
    59. {
    60. //向上更新
    61. cur = parent;
    62. parent = parent->_parent;
    63. }
    64. //如果此时parent的平衡因子为2或-2,那么需要通过旋转调平衡
    65. else if (parent->_bf == 2 || parent->_bf == -2)
    66. {
    67. //左单旋
    68. if (parent->_bf == 2 && cur->_bf == 1)
    69. {
    70. RotateL(parent);
    71. }
    72. //右单旋
    73. if(parent->_bf == -2 && cur->_bf == -1)
    74. {
    75. RotateR(parent);
    76. }
    77. //先右单旋,再左单旋
    78. if (parent->_bf == 2 && cur->_bf == -1)
    79. {
    80. RotateRL(parent);
    81. }
    82. //先左单旋,再右单旋
    83. if (parent->_bf == -2 && cur->_bf == 1)
    84. {
    85. RotateLR(parent);
    86. }
    87. break;//忘记写了
    88. }
    89. else
    90. {
    91. assert(false);
    92. }
    93. }
    94. return true;
    95. }

    五、AVL树判断是否平衡

    1. bool isBalance()
    2. {
    3. return _isBalance(_root);
    4. }
    5. int Height(Node* root)
    6. {
    7. if (root == nullptr)
    8. return 0;
    9. int lh = Height(root->_left);
    10. int rh = Height(root->_right);
    11. return lh > rh ? lh + 1 : rh + 1;
    12. }
    13. bool _isBalance(Node* root)
    14. {
    15. if (root == nullptr)
    16. return true;
    17. int leftHeight = Height(root->_left);
    18. int rightHeight = Height(root->_right);
    19. int diff = abs(rightHeight - leftHeight);
    20. return diff <= 1 && _isBalance(root->_left) && _isBalance(root->_right);
    21. }

    六、AVL树的验证

    1. int main()
    2. {
    3. //常规场景
    4. AVLTree<int, int>* root1 = new AVLTree<int, int>();
    5. int a1[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    6. for (auto e : a1)
    7. {
    8. root1->insert(make_pair(e, e));
    9. }
    10. root1->InOrder();
    11. cout << "isBalance: " << root1->isBalance() << endl;
    12. //特殊场景
    13. AVLTree<int, int>* root2 = new AVLTree<int, int>();
    14. int a2[] = { 4,2,6,1,3,5,15,7,16,14 };
    15. for (auto e : a2)
    16. {
    17. root2->insert(make_pair(e, e));
    18. }
    19. root2->InOrder();
    20. cout << "isBalance: " << root2->isBalance() << endl;
    21. //随机数
    22. const int N = 100000;
    23. vector<int> v;
    24. v.reserve(N);
    25. srand(time(0));
    26. for (int i = 0; i < N; i++)
    27. {
    28. int n = rand();
    29. v.push_back(n);
    30. }
    31. AVLTree<int, int>* root3 = new AVLTree<int, int>();
    32. for (auto e : v)
    33. {
    34. root3->insert(make_pair(e, e));
    35. }
    36. //root->InOrder();
    37. cout << "isBalance: " << root3->isBalance() << endl;
    38. return 0;
    39. }

    运行结果:

  • 相关阅读:
    国际版腾讯云阿里云免费开户:全站加快 DCDN 重磅发布!打造新一代加快引擎
    黑窗口连接远程服务
    【004】Shell脚本以怎样的方式执行?
    Qt MinGW opencv环境配置测试
    web前端框架JS学习之JavaScript类型转换
    【DevOps】OpenVPN 实现分流的几种方法和实战
    2022“杭电杯”中国大学生算法设计超级联赛(5)签到题3题
    38.cuBLAS开发指南中文版--cuBLAS中的Level-2函数her2()
    chrome历史版本下载
    SpringBoot 开放HTTPS HTTP ,并且强制HTTP转HTTPS端口
  • 原文地址:https://blog.csdn.net/weixin_50601177/article/details/133469348