• 手撕红黑树


    学了很久编程了,红黑树在我们耳边早就如雷贯耳,都说他是数据结构中最难的几种结构了,但是,实际上学会了之后,你会发现他还是很简单的,个人认为他还没有AVL树的旋转难,好了,老规矩,来上代码:

    1. #pragma once
    2. #pragma once
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. using namespace std;
    10. namespace cc
    11. {
    12. enum colour
    13. {
    14. RED,
    15. BLACK
    16. };
    17. template<class K, class V>
    18. struct RBtreenode
    19. {
    20. colour _col;
    21. pair _val;
    22. RBtreenode* _left;
    23. RBtreenode* _right;
    24. RBtreenode* _parent;
    25. RBtreenode(const pair& x)
    26. :_val(x)
    27. , _left(nullptr)
    28. , _right(nullptr)
    29. , _parent(nullptr)
    30. , _col(RED)
    31. {}
    32. };
    33. template<class K, class V>
    34. class RBtree
    35. {
    36. public:
    37. typedef RBtreenode node;
    38. void reor(node* parent)
    39. {
    40. node* sub = parent->_left;
    41. node* subr = sub->_right;
    42. if (_root == parent)
    43. {
    44. _root = sub;
    45. sub->_parent = nullptr;
    46. sub->_right = parent;
    47. parent->_parent = sub;
    48. parent->_left = subr;
    49. if (subr)
    50. subr->_parent = parent;
    51. }
    52. else
    53. {
    54. node* pparent = parent->_parent;
    55. if (pparent->_left == parent)
    56. pparent->_left = sub;
    57. else
    58. pparent->_right = sub;
    59. sub->_parent = pparent;
    60. sub->_right = parent;
    61. parent->_parent = sub;
    62. parent->_left = subr;
    63. if (subr)
    64. subr->_parent = parent;
    65. }
    66. }
    67. void reol(node* parent)
    68. {
    69. node* sub = parent->_right;
    70. node* subl = sub->_left;
    71. if (_root == parent)
    72. {
    73. _root = sub;
    74. sub->_parent = nullptr;
    75. sub->_left = parent;
    76. parent->_parent = sub;
    77. parent->_right = subl;
    78. if (subl)
    79. subl->_parent = parent;
    80. }
    81. else
    82. {
    83. node* pparent = parent->_parent;
    84. if (pparent->_left = parent)
    85. pparent->_left = sub;
    86. else
    87. pparent->_right = sub;
    88. sub->_parent = pparent;
    89. sub->_left = parent;
    90. parent->_parent = sub;
    91. parent->_right = subl;
    92. if (subl)
    93. subl->_parent = parent;
    94. }
    95. }
    96. bool insert(const pair& x)
    97. {
    98. if (_root == nullptr)
    99. {
    100. _root = new node(x);
    101. _root->_col = BLACK;
    102. return true;
    103. }
    104. node* parent = nullptr;
    105. node* cur = _root;
    106. while (cur)
    107. {
    108. if (x.first < cur->_val.first)
    109. {
    110. parent = cur;
    111. cur = cur->_left;
    112. }
    113. else if (x.first > cur->_val.first)
    114. {
    115. parent = cur;
    116. cur = cur->_right;
    117. }
    118. else
    119. return false;
    120. }
    121. cur = new node(x);
    122. if (parent->_val.first > x.first)
    123. parent->_left = cur;
    124. else
    125. parent->_right = cur;
    126. cur->_parent = parent;
    127. node* grandfather = parent->_parent;
    128. while (parent && parent->_col == RED)
    129. {
    130. if (grandfather->_left == parent)
    131. {
    132. node* uncle = grandfather->_right;
    133. //情况一:只染色
    134. if (uncle && uncle->_col == RED)
    135. {
    136. uncle->_col = BLACK;
    137. parent->_col = BLACK;
    138. grandfather->_col = RED;
    139. if (grandfather == _root)
    140. {
    141. grandfather->_col = BLACK;
    142. break;
    143. }
    144. }
    145. //情况二+三:旋转+染色
    146. else if (uncle && uncle->_col == BLACK)
    147. {
    148. if (parent->_left == cur)
    149. {
    150. //单旋
    151. reor(grandfather);
    152. //染色
    153. grandfather->_col = RED;
    154. parent->_col = BLACK;
    155. }
    156. else
    157. {
    158. //双旋
    159. reol(parent);
    160. reor(grandfather);
    161. //染色
    162. cur->_col = BLACK;
    163. //爷爷节点变红
    164. grandfather->_col = RED;
    165. }
    166. break;
    167. }
    168. else if (uncle == nullptr)
    169. {
    170. if (parent->_left == cur)
    171. {
    172. reor(grandfather);
    173. grandfather->_col = RED;
    174. parent->_col = BLACK;
    175. }
    176. else
    177. {
    178. reol(parent);
    179. reor(grandfather);
    180. grandfather->_col = RED;
    181. cur->_col = BLACK;
    182. }
    183. break;
    184. }
    185. }
    186. else
    187. {
    188. node* uncle = grandfather->_left;
    189. if (uncle && uncle->_col == RED)
    190. {
    191. uncle->_col = BLACK;
    192. parent->_col = BLACK;
    193. grandfather->_col = RED;
    194. if (_root == grandfather)
    195. {
    196. grandfather->_col = BLACK;
    197. break;
    198. }
    199. }
    200. else if (uncle && uncle->_col == BLACK)
    201. {
    202. if (parent->_left == cur)
    203. {
    204. reor(parent);
    205. reol(grandfather);
    206. grandfather->_col = RED;
    207. cur->_col = BLACK;
    208. }
    209. else
    210. {
    211. reol(grandfather);
    212. grandfather->_col = RED;
    213. parent->_col = BLACK;
    214. }
    215. break;
    216. }
    217. else if (uncle == nullptr)
    218. {
    219. if (parent->_left = cur)
    220. {
    221. reor(parent);
    222. reol(grandfather);
    223. cur->_col = BLACK;
    224. grandfather->_col = RED;
    225. }
    226. else
    227. {
    228. reol(grandfather);
    229. parent->_col = BLACK;
    230. grandfather->_col = RED;
    231. }
    232. break;
    233. }
    234. }
    235. cur = grandfather;
    236. parent = cur->_parent;
    237. grandfather = parent->_parent;
    238. }
    239. return true;
    240. }
    241. bool check()
    242. {
    243. return _check(_root);
    244. }
    245. void print()
    246. {
    247. prin(_root);
    248. }
    249. void prin(node* root,int num)
    250. {
    251. if (root == nullptr)
    252. return;
    253. if (root->_col == BLACK)
    254. num++;
    255. if (root->_left == root->_right &&root->_left == nullptr)
    256. cout << num << endl;
    257. prin(root->_left,num);
    258. prin(root->_right,num);
    259. }
    260. bool _check(node* root)
    261. {
    262. if (root == nullptr)
    263. {
    264. if (root->_col != BLACK)
    265. exit(-1);
    266. return true;
    267. }
    268. if (root->_parent && root->_parent->_col == RED)
    269. {
    270. cout << "异常退出" << endl;
    271. exit(-1);
    272. }
    273. int num = 0;
    274. prin(root, num);
    275. }
    276. private:
    277. node* _root = nullptr;
    278. };
    279. }

    其实和AVL树的代码差不多,唯一不同的是,我们没有平衡因子了,但是有颜色。

    下面来说说红黑树的规则:

    1.一个节点不是红色就是黑色

    2.根节点必须是黑色

    3.红色节点的两个孩子必须是黑色节点

    4.每条路径的黑色节点个数相同

    5.叶子结点(NIL节点)是黑色的

    上面就是红黑树的规则,红黑树的代码就在上面,现在说一下红黑树的具体实现规则:

    1.如果叔叔节点存在且叔叔节点为红色,那么,把父节点和叔叔节点染成黑色,组父节点染成红色,如果此时的祖父节点是根节点,那么,就在把祖父节点染成黑色。如果不是,就把新插入的节点更新成祖父节点,依次往上更新,直到父节点为空或是父节点的颜色为黑色就停止。

    2.如果叔叔节点存在,且叔叔节点是黑色的,那么此时就要判断新插入的节点在父节点的左还右,如果父节点,祖父节点,新插入的节点成一条线,那么此时就是单旋,然后旋转完成之后把父节点染成黑色,祖父节点染成红色。

    3.如果叔叔节点存在,且为黑色,新插入节点与父节点,祖父节点形成折线,那么此时应该是双旋,旋转完成之后,把新插入的节点染成黑色,祖父节点染成红色。

    4.如果叔叔节点不存在,那就看是上面的额那种情况,是那种旋转,找到对应的旋转就好了。

    以上就是实现红黑树代码的具体细节。

    AVL树和红黑树的对比:

    其实AVL树和红黑树两个各有各的好处,是的,个人认为两个各有各的好处,因为AVL对树高比较严格,所以导致旋转点额次数就多,所以就会有额外的消耗,但是红黑树就没有这么多的消耗了,因为红黑树的上面几个规则,导致红黑树最长路径不得超过对短路径的两倍,所以,红黑树也会旋转,但是插入同等节点的条件下,红黑树旋转点次数肯定比AVL树少,但是AVL树是严格的logn,而红黑树是不太严格的logn,所以我说是各有各的好。

    以上就是红黑树的规则讲解以及代码实现。希望大家能够多多支持!!谢谢!

  • 相关阅读:
    VR全景校园:不被简单定义的校园展示,看的不止“一面”
    力扣 430. 扁平化多级双向链表
    通过使用Portainer来管理Docke环境以及使用私人镜像仓库
    CentOS常见命令详解
    数据库知识
    Redux使用详解(二)--react-redux的使用
    必知必会的22种设计模式(GO语言)
    Kafka磁盘写满日志清理操作
    速览默默发展的Web3邮箱赛道
    Delaunay三角网
  • 原文地址:https://blog.csdn.net/huichaochao/article/details/132653177