当前位置:   article > 正文

【C++红黑树】带图详细解答红黑树的插入,测试自己的红黑树是否正确的代码_红黑树測試

红黑树測試

目录

1.红黑树的概念

1.1红黑树的特性(4+1)

2.红黑树的框架 

3.红黑树的插入 

        3.1parent在grandfather的左边

         3.1parent在grandfather的右边

 4.测试自己的红黑树是不是平衡的


1.红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是RedBlack。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,确保红黑树没有一条路径会比其他路径长出俩倍,因而是接近平衡的。

  • 所以它是一个弱平衡二叉搜索树,AVL1树是一个严格的平衡二叉搜索树

1.1红黑树的特性(4+1)

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的所有的孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的路径上,均包含相同数目的黑色结点

每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

  • 我认为这一条只是标记的作用,让我们更好分别每一条路径

 

2.红黑树的框架 

  1. //枚举颜色
  2. enum Colour
  3. {
  4. RED,
  5. BLACK,
  6. };
  7. template<class K, class V>
  8. struct RBtreeNode
  9. {
  10. RBtreeNode(const pair<K, V>& kv)
  11. :_left(nullptr)
  12. ,_right(nullptr)
  13. ,_parent(nullptr)
  14. ,_kv(kv)
  15. //初始化给红色,红色比黑色更好处理
  16. ,_col(RED)
  17. {}
  18. //三叉链
  19. RBtreeNode<K, V>* _left;
  20. RBtreeNode<K, V>* _right;
  21. RBtreeNode<K, V>* _parent;
  22. //数据
  23. pair<K,V> _kv;
  24. //颜色
  25. Colour _col;
  26. };
  27. template<class K,class V>
  28. class RBtree
  29. {
  30. typedef RBtreeNode<K,V> Node;
  31. public:
  32. RBtree()
  33. :_root(nullptr)
  34. {}
  35. //旋转
  36. void RotateL(Node* parent)
  37. void RotateR(Node* parent)
  38. //插入
  39. pair<Node*, bool> Insert(const pair<K, V> kv)
  40. //寻找
  41. Node* Find(const K& key)
  42. //测试自己的写的的红黑树,是否合适
  43. bool CheckBalance()
  44. private:
  45. Node* _root;
  46. };

3.红黑树的插入 

  1. pair<Node*, bool> Insert(const pair<K, V> kv)
  2. //是否为空树
  3. {
  4. if (_root == nullptr)
  5. {
  6. _root = new Node(kv);
  7. _root->_col = BLACK;
  8. return make_pair(_root, true);
  9. }
  10. Node* cur = _root,*parent=_root;
  11. while (cur)
  12. {
  13. if (cur->_kv.first < kv.first)
  14. {
  15. parent = cur;
  16. cur = cur->_right;
  17. }
  18. else if (cur->_kv.first > kv.first)
  19. {
  20. parent = cur;
  21. cur = cur->_left;
  22. }
  23. else
  24. {
  25. return make_pair(cur, false);
  26. }
  27. }
  28. Node* newnode = new Node(kv);
  29. newnode->_col = RED;
  30. if (parent->_kv.first < kv.first)
  31. {
  32. parent->_right = newnode;
  33. newnode->_parent = parent;
  34. }
  35. else
  36. {
  37. parent->_left = newnode;
  38. newnode->_parent = parent;
  39. }
  40. cur = newnode;
  41. while (parent && parent->_col == RED)
  42. {
  43. // 如果父亲存在,且颜色为红色就需要处理
  44. Node* grandfather = parent->_parent;
  45. if (parent == grandfather->_left)
  46. {
  47. // 关键是看叔叔
  48. Node* uncle = grandfather->_right;
  49. // 情况1:uncle存在且为红
  50. if (uncle&&uncle->_col == RED)
  51. {
  52. parent->_col = uncle->_col = BLACK;
  53. grandfather->_col = RED;
  54. // 继续往上处理
  55. cur = grandfather;
  56. parent = cur->_parent;
  57. }
  58. else// 情况2+3:uncle不存在 uncle存在且为黑
  59. {
  60. // 情况2:单旋
  61. if (cur == parent->_left)
  62. {
  63. RotateR(grandfather);
  64. parent->_col = BLACK ;
  65. grandfather->_col = RED;
  66. }
  67. // 情况3:双旋
  68. else
  69. {
  70. RotateL(parent);
  71. RotateR(grandfather);
  72. cur->_col = BLACK;
  73. grandfather->_col = RED;
  74. }
  75. //最上面的节点已经变黑了,不用继续
  76. break;
  77. }
  78. }
  79. // 如果父亲存在,且颜色为红色就需要处理
  80. else
  81. {
  82. // 关键是看叔叔
  83. Node* uncle = grandfather->_left;
  84. // 情况1:uncle存在且为红
  85. if (uncle && uncle->_col == RED)
  86. {
  87. parent->_col = uncle->_col = BLACK;
  88. grandfather->_col = RED;
  89. // 继续往上处理
  90. cur = grandfather;
  91. parent = cur->_parent;
  92. }
  93. else // 情况2 + 3:uncle不存在 uncle存在且为黑
  94. {
  95. // 情况2:单旋
  96. if (cur == parent->_right)
  97. {
  98. RotateL(grandfather);
  99. parent->_col = BLACK;
  100. grandfather->_col = RED;
  101. }
  102. // 情况3:双旋
  103. else
  104. {
  105. RotateR(parent);
  106. RotateL(grandfather);
  107. cur->_col = BLACK;
  108. grandfather->_col = RED;
  109. }
  110. }
  111. break;
  112. }
  113. }
  114. _root->_col = BLACK;
  115. return make_pair(newnode, true);
  116. }

 插入整体逻辑:

  1. 如果还没有元素是一课空树,直接插入即可;如果有元素,按pair的first(key)和比较的节点比较结果为大说明为空的那个位置在右边,和比较的节点比较的结果小说明为空的哪个位置在左边;如果相等说明已经有这个元素了,二叉搜索树不支持冗余,插入失败则,返回一个pair类第一个成员为那个相同元素的map的迭代器和第二个成员为false的pair类迭代器;
  2. 不知道这个已经找到的位置在父节点的左边还是右边,需要判断一下,然后插入元素;
  3. 考虑变色

3.1不平衡处理

如果有父亲且父亲为红色说明不平衡,就一直向上调整,直到cur到头节点或者parent为黑色

1.第一种情况:有uncle并且uncle为红色处理:parent和uncle变为黑色,grandfather变红色

  • 一直向上调整可能会让头节点变红,那么就在循环外把头节点处理一下

 2.第二种情况,没有uncle或者有uncle且为黑色,有uncle一定是第一种情况变化而来

3.1parent在grandfather的左边

这种情况单纯的变色已经做不到平衡了,怎么办?

旋转处理:parent在grandfather的左边,右单旋和左右双旋

 3.1parent在grandfather的右边

  • 逻辑和在左边是一样的,大家可以自己尝试画一下
  • 旋转我在AVL树右详细解答http://t.csdn.cn/AlRzI

旋转代码:

  1. void RotateL(Node* parent)
  2. {
  3. Node* subR = parent->_right;
  4. Node* subRL = subR->_left;
  5. parent->_right = subRL;
  6. if (subRL)
  7. {
  8. subRL->_parent = parent;
  9. }
  10. subR->_left = parent;
  11. Node* parentParent = parent->_parent;
  12. parent->_parent = subR;
  13. if (parent == _root)
  14. {
  15. _root = subR;
  16. _root->_parent = nullptr;
  17. }
  18. else
  19. {
  20. if (parentParent->_left == parent)
  21. {
  22. parentParent->_left = subR;
  23. }
  24. else
  25. {
  26. parentParent->_right = subR;
  27. }
  28. subR->_parent = parentParent;
  29. }
  30. }
  31. void RotateR(Node* parent)
  32. {
  33. Node* subL = parent->_left;
  34. Node* subLR = subL->_right;
  35. parent->_left = subLR;
  36. if (subLR)
  37. subLR->_parent = parent;
  38. subL->_right = parent;
  39. Node* parentParent = parent->_parent;
  40. parent->_parent = subL;
  41. if (parent == _root)
  42. {
  43. _root = subL;
  44. _root->_parent = nullptr;
  45. }
  46. else
  47. {
  48. if (parentParent->_left == parent)
  49. parentParent->_left = subL;
  50. else
  51. parentParent->_right = subL;
  52. subL->_parent = parentParent;
  53. }
  54. }

 4.测试自己的红黑树是不是平衡的

  • 测试了头节点是不是黑色,是否有连续的红节点,每条路径上的黑节点
  1. bool _CheckBalance(Node* root,int LeftNum,int count)
  2. {
  3. if (root == nullptr)
  4. {
  5. if (count != LeftNum)
  6. {
  7. return false;
  8. }
  9. return true;
  10. }
  11. if (root->_col == RED && root->_parent->_col == RED)
  12. {
  13. cout << "存在连续的红色节点" << endl;
  14. return false;
  15. }
  16. if (root->_col == BLACK)
  17. {
  18. count++;
  19. }
  20. return _CheckBalance(root->_left, LeftNum, count) &&
  21. _CheckBalance(root->_right, LeftNum, count);
  22. }
  23. bool CheckBalance()
  24. {
  25. if (_root == nullptr)
  26. {
  27. //空树是红黑树
  28. return true;
  29. }
  30. else if(_root->_col==RED)
  31. {
  32. cout << "根节点是红色的" << endl;
  33. return false;
  34. }
  35. else
  36. {
  37. int LeftNum = 0;
  38. Node* left = _root;
  39. // 找最左路径做黑色节点数量参考值
  40. while (left)
  41. {
  42. if (left->_col == BLACK)
  43. {
  44. LeftNum++;
  45. }
  46. left = left->_left;
  47. }
  48. int count = 0;
  49. return _CheckBalance(_root, LeftNum, count);
  50. }
  51. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/246181
推荐阅读
相关标签
  

闽ICP备14008679号