• C++简单实现红黑树


    目录

    一、概念

    二、红黑树的性质

    三、红黑树的定义

    四、红黑树的插入操作

    情况一(叔叔节点存在且为红色)——变色+向上调整:

    情况二(叔叔节点不存在或为黑色)——旋转+变色:

    2.1叔叔节点不存在

    2.2叔叔节点为黑色

    插入的代码实现:

    五、红黑树的验证

    六、红黑树完整代码


    一、概念

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

    二、红黑树的性质

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

    三、红黑树的定义

    1. enum Colour
    2. {
    3. RED,BLACK
    4. };
    5. template<class K, class V>
    6. struct RBTreeNode
    7. {
    8. RBTreeNode(const pair& kv)
    9. :_kv(kv)
    10. ,_right(nullptr)
    11. ,_left(nullptr)
    12. ,_parent(nullptr)
    13. ,_col(RED)//默认插入节点为红色,如果为黑色,就会对其他路径也造成影响
    14. {}
    15. pair _kv;
    16. RBTreeNode* _right;
    17. RBTreeNode* _left;
    18. RBTreeNode* _parent;
    19. Colour _col;
    20. };

    C++STL中的set和map底层就是使用红黑树实现的,而map是存放键值对的,所以我们给红黑树的节点中的值存放一个键值对,以及左右孩子的指针和指向父节点的指针,还有一个存放颜色的标记。

    四、红黑树的插入操作

    红黑树的插入首先和普通二叉搜索树的插入操作一样,新建一个节点,左节点的值小于根,右节点的值大于根,找到位置进行插入。插入后应如果破坏了红黑树的性质,就需要进行调整。

    因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何
    性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连
    在一起的红色节点,此时需要对红黑树分情况来讨论:

    我们给出一个约定:cur为当前节点,p为父亲节点,g为祖父节点,u为叔叔节点

    情况一(叔叔节点存在且为红色)——变色+向上调整:

    将p和u改成黑色,将g改为红色

    此时有三种情况:

    1、g没有父亲节点,直接变成黑色就可以,插入结束;

    2、g有父亲节点,且父亲为黑色,插入结束;

    3、g有父亲节点,且父亲为红色(违反了红色节点不能连续的性质),需要向上调整。

    情况二(叔叔节点不存在或为黑色)——旋转+变色:

    2.1叔叔节点不存在

    如果cur在parent的左边——右旋:

    cur在parent的右边——先左旋再右旋:

    2.2叔叔节点为黑色

    如果cur在parent的左边——右旋:

    cur在parent的右边——先左旋再右旋:

    以上插入操作是p在g节点左边的情况,p在g节点右边的情况与以上插入过程类似,仅仅是镜像翻转一下。

    插入的代码实现:

    左旋代码:

    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. }

    右旋代码:

    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. }

    插入代码:

    1. bool insert(const pair& kv)
    2. {
    3. //如果root为空
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(kv);
    7. _root->_col = BLACK;
    8. return true;
    9. }
    10. //插入
    11. Node* cur = _root;
    12. Node* parent = cur;
    13. while (cur)
    14. {
    15. if (cur->_kv.first < kv.first)
    16. {
    17. parent = cur;
    18. cur = cur->_right;
    19. }
    20. else if (cur->_kv.first > kv.first)
    21. {
    22. parent = cur;
    23. cur = cur->_left;
    24. }
    25. else
    26. {
    27. return false;
    28. }
    29. }
    30. cur = new Node(kv);//插入节点
    31. if (parent->_kv.first < kv.first)
    32. {
    33. parent->_right = cur;
    34. }
    35. else
    36. {
    37. parent->_left = cur;
    38. }
    39. cur->_parent = parent;
    40. //插入完毕,开始调整颜色
    41. while (parent && parent->_col == RED)
    42. {
    43. Node* grandfather = parent->_parent;
    44. //叔叔在右
    45. if (grandfather->_left == parent)
    46. {
    47. Node* uncle = grandfather->_right;
    48. //叔叔存在且为红色——变色
    49. if (uncle && uncle->_col == RED)
    50. {
    51. parent->_col = BLACK;
    52. uncle->_col = BLACK;
    53. grandfather->_col = RED;
    54. //向上更新
    55. cur = grandfather;
    56. parent = cur->_parent;
    57. }
    58. //叔叔不存在或者为黑色——旋转+变色
    59. else
    60. {
    61. //右单旋即可
    62. if (parent->_left == cur)
    63. {
    64. RotateR(grandfather);
    65. //变色
    66. parent->_col = BLACK;
    67. grandfather->_col = RED;
    68. }
    69. //先左单旋,后右单旋
    70. else
    71. {
    72. RotateL(parent);
    73. RotateR(grandfather);
    74. //变色
    75. cur->_col = BLACK;
    76. grandfather->_col = RED;
    77. }
    78. break;
    79. }
    80. }
    81. //叔叔在左
    82. else
    83. {
    84. Node* uncle = grandfather->_left;
    85. //uncle存在且为红色——变色
    86. if (uncle && uncle->_col == RED)
    87. {
    88. parent->_col = BLACK;
    89. uncle->_col = BLACK;
    90. grandfather->_col = RED;
    91. //向上更新
    92. cur = grandfather;
    93. parent = cur->_parent;
    94. }
    95. //uncle不存在或为黑色——旋转+变色
    96. else
    97. {
    98. //左单旋即可
    99. if (parent->_right == cur)
    100. {
    101. RotateL(grandfather);
    102. //变色
    103. grandfather->_col = RED;
    104. parent->_col = BLACK;
    105. }
    106. //先右单旋,再左单旋
    107. else
    108. {
    109. RotateR(parent);
    110. RotateL(grandfather);
    111. //变色
    112. cur->_col = BLACK;
    113. grandfather->_col = RED;
    114. }
    115. break;
    116. }
    117. }
    118. }
    119. _root->_col = BLACK;
    120. return true;
    121. }

    五、红黑树的验证

    1. bool isBalance()
    2. {
    3. return _isBalance(_root);
    4. }
    5. bool checkcolour(Node* root, int benckmark, int blackcount)
    6. {
    7. if (root == nullptr)
    8. {
    9. if (blackcount != benckmark)
    10. return false;
    11. return true;
    12. }
    13. if (root->_col == RED && root->_parent && root->_parent->_col == RED)
    14. return false;
    15. if (root->_col == BLACK)
    16. ++benckmark;
    17. return checkcolour(root->_left, benckmark, blackcount)
    18. && checkcolour(root->_right, benckmark, blackcount);
    19. }
    20. bool _isBalance(Node* root)
    21. {
    22. if (root == nullptr)
    23. return true;
    24. if (root->_col != BLACK)
    25. return false;
    26. Node* cur = root;
    27. //求树中最左路径黑色节点的个数
    28. while (cur)
    29. {
    30. if (cur->_col == BLACK)
    31. ++blackcount;
    32. cur = cur->_left;
    33. }
    34. return checkcolour(_root, 0, blackcount);
    35. }

    六、红黑树完整代码

    1. #pragma once
    2. #include
    3. #include
    4. using namespace std;
    5. enum Colour
    6. {
    7. RED,BLACK
    8. };
    9. template<class K, class V>
    10. struct RBTreeNode
    11. {
    12. RBTreeNode(const pair& kv)
    13. :_kv(kv)
    14. ,_right(nullptr)
    15. ,_left(nullptr)
    16. ,_parent(nullptr)
    17. ,_col(RED)//默认插入节点为红色,如果为黑色,就会对其他路径也造成影响
    18. {}
    19. pair _kv;
    20. RBTreeNode* _right;
    21. RBTreeNode* _left;
    22. RBTreeNode* _parent;
    23. Colour _col;
    24. };
    25. /*
    26. * 红黑树插入思路——关键在于uncle节点:
    27. * 分为两大类:
    28. * 一、如果uncle存在且为红色——仅仅变色即可
    29. *
    30. * g(黑) g(红)
    31. * p(红) u(红) -------> p(黑) u(黑) ------->继续向上更新
    32. * c(红) c(红)
    33. *
    34. *
    35. * 二、如果uncle不存在或为黑色——旋转加变色
    36. *
    37. * 情况一: g(黑) p(红)
    38. * p(红) NULL/黑 -------> c(红) g(黑)
    39. * c(红)
    40. *
    41. * 仅仅右旋即可,g变成红色; p变成黑色; break;
    42. *
    43. * 情况二: g(黑) g(黑) c(红)
    44. * p(红) NULL/黑 -------> 先左旋 c(红) -------> p(红) g(黑)
    45. * c(红) p(红)
    46. *
    47. * c变成黑色,g变成红色,break;
    48. *
    49. * 情况三:情况一的对称图形
    50. * 情况四:情况二的对称图形
    51. *
    52. */
    53. template<class K, class V>
    54. class RBTree
    55. {
    56. typedef RBTreeNode Node;
    57. public:
    58. RBTree()
    59. :_root(nullptr)
    60. {}
    61. void InOrder()
    62. {
    63. cout << "InOrder: ";
    64. _InOrder(_root);
    65. cout << endl;
    66. }
    67. bool insert(const pair& kv)
    68. {
    69. //如果root为空
    70. if (_root == nullptr)
    71. {
    72. _root = new Node(kv);
    73. _root->_col = BLACK;
    74. return true;
    75. }
    76. //插入
    77. Node* cur = _root;
    78. Node* parent = cur;
    79. while (cur)
    80. {
    81. if (cur->_kv.first < kv.first)
    82. {
    83. parent = cur;
    84. cur = cur->_right;
    85. }
    86. else if (cur->_kv.first > kv.first)
    87. {
    88. parent = cur;
    89. cur = cur->_left;
    90. }
    91. else
    92. {
    93. return false;
    94. }
    95. }
    96. cur = new Node(kv);//插入节点
    97. if (parent->_kv.first < kv.first)
    98. {
    99. parent->_right = cur;
    100. }
    101. else
    102. {
    103. parent->_left = cur;
    104. }
    105. cur->_parent = parent;
    106. //插入完毕,开始调整颜色
    107. while (parent && parent->_col == RED)
    108. {
    109. Node* grandfather = parent->_parent;
    110. //叔叔在右
    111. if (grandfather->_left == parent)
    112. {
    113. Node* uncle = grandfather->_right;
    114. //叔叔存在且为红色——变色
    115. if (uncle && uncle->_col == RED)
    116. {
    117. parent->_col = BLACK;
    118. uncle->_col = BLACK;
    119. grandfather->_col = RED;
    120. //向上更新
    121. cur = grandfather;
    122. parent = cur->_parent;
    123. }
    124. //叔叔不存在或者为黑色——旋转+变色
    125. else
    126. {
    127. //右单旋即可
    128. if (parent->_left == cur)
    129. {
    130. RotateR(grandfather);
    131. //变色
    132. parent->_col = BLACK;
    133. grandfather->_col = RED;
    134. }
    135. //先左单旋,后右单旋
    136. else
    137. {
    138. RotateL(parent);
    139. RotateR(grandfather);
    140. //变色
    141. cur->_col = BLACK;
    142. grandfather->_col = RED;
    143. }
    144. break;
    145. }
    146. }
    147. //叔叔在左
    148. else
    149. {
    150. Node* uncle = grandfather->_left;
    151. //uncle存在且为红色——变色
    152. if (uncle && uncle->_col == RED)
    153. {
    154. parent->_col = BLACK;
    155. uncle->_col = BLACK;
    156. grandfather->_col = RED;
    157. //向上更新
    158. cur = grandfather;
    159. parent = cur->_parent;
    160. }
    161. //uncle不存在或为黑色——旋转+变色
    162. else
    163. {
    164. //左单旋即可
    165. if (parent->_right == cur)
    166. {
    167. RotateL(grandfather);
    168. //变色
    169. grandfather->_col = RED;
    170. parent->_col = BLACK;
    171. }
    172. //先右单旋,再左单旋
    173. else
    174. {
    175. RotateR(parent);
    176. RotateL(grandfather);
    177. //变色
    178. cur->_col = BLACK;
    179. grandfather->_col = RED;
    180. }
    181. break;
    182. }
    183. }
    184. }
    185. _root->_col = BLACK;
    186. return true;
    187. }
    188. bool isBalance()
    189. {
    190. return _isBalance(_root);
    191. }
    192. private:
    193. bool checkcolour(Node* root, int benckmark, int blackcount)
    194. {
    195. if (root == nullptr)
    196. {
    197. if (blackcount != benckmark)
    198. return false;
    199. return true;
    200. }
    201. if (root->_col == RED && root->_parent && root->_parent->_col == RED)
    202. return false;
    203. if (root->_col == BLACK)
    204. ++benckmark;
    205. return checkcolour(root->_left, benckmark, blackcount)
    206. && checkcolour(root->_right, benckmark, blackcount);
    207. }
    208. bool _isBalance(Node* root)
    209. {
    210. if (root == nullptr)
    211. return true;
    212. if (root->_col != BLACK)
    213. return false;
    214. Node* cur = root;
    215. while (cur)
    216. {
    217. if (cur->_col == BLACK)
    218. ++blackcount;
    219. cur = cur->_left;
    220. }
    221. return checkcolour(_root, 0, blackcount);
    222. }
    223. void RotateL(Node* parent)
    224. {
    225. Node* cur = parent->_right;
    226. Node* curleft = cur->_left;
    227. parent->_right = curleft;
    228. cur->_left = parent;
    229. if (curleft)
    230. curleft->_parent = parent;
    231. Node* ppnode = parent->_parent;
    232. parent->_parent = cur;
    233. if (parent == _root)
    234. {
    235. cur->_parent = nullptr;
    236. _root = cur;
    237. }
    238. else
    239. {
    240. if (ppnode->_left == parent)
    241. {
    242. ppnode->_left = cur;
    243. }
    244. else
    245. {
    246. ppnode->_right = cur;
    247. }
    248. cur->_parent = ppnode;
    249. }
    250. }
    251. void RotateR(Node* parent)
    252. {
    253. Node* cur = parent->_left;
    254. Node* curright = cur->_right;
    255. parent->_left = curright;
    256. cur->_right = parent;
    257. if (curright)
    258. curright->_parent = parent;
    259. Node* ppnode = parent->_parent;
    260. parent->_parent = cur;
    261. if (parent == _root)
    262. {
    263. cur->_parent = nullptr;
    264. _root = cur;
    265. }
    266. else
    267. {
    268. if (ppnode->_left == parent)
    269. {
    270. ppnode->_left = cur;
    271. }
    272. else
    273. {
    274. ppnode->_right = cur;
    275. }
    276. cur->_parent = ppnode;
    277. }
    278. }
    279. void _InOrder(Node* root)
    280. {
    281. if (root == nullptr)
    282. return;
    283. _InOrder(root->_left);
    284. cout << root->_kv.first << " ";
    285. _InOrder(root->_right);
    286. }
    287. private:
    288. Node* _root;
    289. int blackcount = 0;
    290. };

    测试:

    运行结果:

    之后更新红黑树的应用,用红黑树封装map和set。

  • 相关阅读:
    UE5场景逐渐变亮问题
    【FLASH存储器系列二】非易失性存储器基本原理之EEPROM和FLASH
    网络安全(黑客)自学
    Java 数据结构 ---》 泛型
    Springboot:如何搭建起自己第一个Springboot项目
    TYUT太原理工大学2022需求工程考试简答题
    【无标题】小程序条件判断wx:if=“{{indexof.checkFunDic(item.settingId,‘2‘)}}“
    Python爬虫 -- Selenium库的使用
    循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(2)
    【每日训练】连续最大和
  • 原文地址:https://blog.csdn.net/weixin_50601177/article/details/133386765