当前位置:   article > 正文

数据结构 - 红黑树_红黑树数据结构

红黑树数据结构

目录

一、红黑树概念

二、代码实现

1 节点定义

2 树的定义

3 插入

3.1 情况一:u节点存在且为红

 3.2 情况二:u节点不存在或存在且为黑。

 3.3 代码实现部分

4 验证


一、红黑树概念

        红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。红黑树就能保证其最长路径中节点个数不会超过最短路径节点个数的两倍。

满足性质:

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



二、代码实现

1 节点定义

  1. enum Color { RED, BLACK };
  2. RBTreeNode(const ValueType& data = ValueType())
  3. : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
  4. , _data(data), _color(RED)
  5. {}
  6. RBTreeNode<ValueType>* _pLeft; // 节点的左孩子
  7. RBTreeNode<ValueType>* _pRight; // 节点的右孩子
  8. RBTreeNode<ValueType>* _pParent; // 节点的双亲
  9. ValueType _data; // 节点的值域
  10. Color _color; // 节点的颜色

2 树的定义

  1. template<class ValueType>
  2. class RBTree
  3. {
  4. typedef RBTreeNode<ValueType> Node;
  5. public:
  6. RBTree()
  7. :_root(nullptr)
  8. {}
  9. bool Insert(const ValueType& data);
  10. bool IsBalance();
  11. private:
  12. bool _isBanlance(Node* cur,int banchmark,int blacknum);
  13. void RotateL(Node* parent);
  14. void RotateR(Node* parent);
  15. private:
  16. RBTreeNode<ValueType>* _root;
  17. };

3 插入

         在这里将节点按下图的方式命名,p表示当前节点的父亲节点,u表示叔叔节点,g表示祖父节点。插入节点默认为红节点,如果插入节点的父节点是黑,则红黑树规则不会被破坏,无需任何操作。据此,将节点插入分为两种需要操作的情况,情况一:u节点存在且为红,情况二:u节点不存在或存在且为黑。

        下图是p节点在左,p节点在右的情况是完全对称的,就不在区分出来分析。

3.1 情况一:u节点存在且为红

        将p、u改为黑,g改为红。

         如果g是根节点,则最后g改为黑。如果g是子树的根节点,且该节点的父节点还是红机点,则g是新的cur节点向上判断。

 3.2 情况二:u节点不存在或存在且为黑。

        该情况下二叉树需要旋转。旋转规则跟AVL树类似。又可细分两个情况,cur在p左插入,cur在p右插入。第一种需要g右旋,p改为黑,g改为红,第二种情况先对p左旋就变成了第一种情况。

 3.3 代码实现部分

  1. bool Insert(const ValueType& data)
  2. {
  3. if (_root == nullptr)
  4. {
  5. _root = new Node(data);
  6. _root->_color = BLACK;
  7. return true;
  8. }
  9. //找到插入节点位置
  10. Node* parent = nullptr;
  11. Node* cur = _root;
  12. while (cur)
  13. {
  14. if (cur->_data < data)
  15. {
  16. parent = cur;
  17. cur = cur->_pRight;
  18. }
  19. else if (cur->_data > data)
  20. {
  21. parent = cur;
  22. cur = cur->_pLeft;
  23. }
  24. else
  25. {
  26. return false;
  27. }
  28. }
  29. //插入节点
  30. cur = new Node(data);
  31. if (parent->_data > data)
  32. parent->_pLeft = cur;
  33. else if (parent->_data < data)
  34. parent->_pRight = cur;
  35. else
  36. assert(false);
  37. cur->_pParent = parent;
  38. //控制平衡
  39. while (parent && parent->_color == RED)
  40. {
  41. Node* grandfather = parent->_pParent;
  42. if (parent == grandfather->_pLeft)//父节点在左
  43. {
  44. Node* uncle = grandfather->_pRight;
  45. //uncle存在切为红,往上变色
  46. if (uncle && uncle->_color == RED)
  47. {
  48. parent->_color = uncle->_color = BLACK;
  49. grandfather->_color = RED;
  50. cur = grandfather;
  51. parent = grandfather->_pParent;
  52. }
  53. //uncle不存在或者存在为黑,需要旋转
  54. else
  55. {
  56. if (cur == parent->_pLeft)//需要单旋
  57. {
  58. RotateR(grandfather);
  59. grandfather->_color = RED;
  60. parent->_color = BLACK;
  61. }
  62. else//需要双旋
  63. {
  64. RotateL(parent);
  65. RotateR(grandfather);
  66. grandfather->_color = RED;
  67. cur->_color = BLACK;
  68. }
  69. }
  70. }
  71. else
  72. {
  73. Node* uncle = grandfather->_pLeft;
  74. //uncle存在切为红,往上变色
  75. if (uncle && uncle->_color == RED)
  76. {
  77. parent->_color = uncle->_color = BLACK;
  78. grandfather->_color = RED;
  79. cur = grandfather;
  80. parent = grandfather->_pParent;
  81. }
  82. //uncle不存在或者存在为黑,需要旋转
  83. else
  84. {
  85. if (cur == parent->_pRight)//需要单旋
  86. {
  87. RotateL(grandfather);
  88. grandfather->_color = RED;
  89. parent->_color = BLACK;
  90. }
  91. else//需要双旋
  92. {
  93. RotateR(parent);
  94. RotateL(grandfather);
  95. grandfather->_color = RED;
  96. cur->_color = BLACK;
  97. }
  98. }
  99. }
  100. }
  101. _root->_color = BLACK;
  102. return true;
  103. }
  104. void RotateL(Node* parent)
  105. {
  106. Node* subR = parent->_pRight;
  107. Node* subRL = subR->_pLeft;
  108. parent->_pRight = subRL;
  109. if (subRL)
  110. {
  111. subRL->_pParent = parent;
  112. }
  113. Node* parentParent = parent->_pParent;
  114. subR->_pLeft = parent;
  115. parent->_pParent = subR;
  116. if (_root == parent)
  117. {
  118. _root = subR;
  119. subR->_pParent = nullptr;
  120. }
  121. else
  122. {
  123. if (parentParent->_pLeft == parent)
  124. parentParent->_pLeft = subR;
  125. else
  126. parentParent->_pRight = subR;
  127. subR->_pParent = parentParent;
  128. }
  129. }
  130. void RotateR(Node* parent)
  131. {
  132. Node* subL = parent->_pLeft;
  133. Node* subLR = subL->_pRight;
  134. parent->_pLeft = subLR;
  135. if (subLR)
  136. subLR->_pParent = parent;
  137. Node* parentParent = parent->_pParent;
  138. subL->_pRight = parent;
  139. parent->_pParent = subL;
  140. if (parent == _root)
  141. {
  142. _root = subL;
  143. _root->_pParent = nullptr;
  144. }
  145. else
  146. {
  147. if (parentParent->_pLeft == parent)
  148. parentParent->_pLeft = subL;
  149. else
  150. parentParent->_pRight = subL;
  151. subL->_pParent = parentParent;
  152. }
  153. }

4 验证

        首先验证根节点必须是黑色。遍历最左路径,找到一条路径上的黑色节点数作为参考值。通过递归的方法记录每条路径的黑色节点数,并与参考值比较。同时在遍历路径的时候检查是否出现连续的红色节点。

  1. bool _isBanlance(Node* cur,int banchmark,int blacknum)
  2. {
  3. if (cur == nullptr)
  4. {
  5. if (banchmark == blacknum)
  6. return true;
  7. std::cout << "路径黑色节点数不等" << std::endl;
  8. return false;
  9. }
  10. if (cur->_color == RED && cur->_pParent->_color == RED)
  11. {
  12. std::cout << "出现连续红色节点" << std::endl;
  13. return false;
  14. }
  15. if (cur->_color == BLACK)
  16. blacknum++;
  17. return _isBanlance(cur->_pLeft, banchmark, blacknum)
  18. && _isBanlance(cur->_pRight, banchmark, blacknum);
  19. }
  20. bool IsBalance()
  21. {
  22. if (_root && _root->_color == RED)
  23. {
  24. std::cout << "根节点是红色" << std::endl;
  25. return false;
  26. }
  27. int banchmark = 0;
  28. Node* cur = _root;
  29. while (cur)
  30. {
  31. if (cur->_color == BLACK)
  32. banchmark++;
  33. cur = cur->_pLeft;
  34. }
  35. int blacknum = 0;
  36. return _isBanlance(_root,banchmark,blacknum);
  37. }

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

闽ICP备14008679号