众所周知,红黑树是用途很广的平衡二叉搜索树,用过的都说好。所以我们来看看红黑树的是怎么实现的吧。

红黑树顾名思义,通过红与黑两种颜色来给每个节点上色。其中根结点和叶子结点一定是黑色的,并且红色结点的两个孩子一定是黑色的,每个结点到所有后代叶子的简单路径上,均包含相同数目的黑色结点(黑高bh)。

这里和其他树有些区别的是,红黑树的叶子结点并不包含关键字,它只是用来维持红黑树的性质。所以包含关键字的结点都是内部结点。

这样的性质也带来了很多有意思的现象。下面我们忽略所谓的叶子结点来看看。

1.红色结点的孩子要么没有,要么是两个黑色结点,不会有单个孩子结点的时候。

2.如果某个结点只有一个孩子结点,那么那个孩子结点一定是红色的。

3.用吸收的角度去看,即黑色结点可以吸收它的红色孩子结点,红黑树就像一个2-3-4树。

下面我们来看看代码吧,代码用了一个小技巧,即所有的叶子结点都用一个nil结点来表示,指向nullptr的指针现在全部指向nil。

代码如下:(仅供参考)

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class RBT {
  5. private :
  6. enum {RED = , BLACK};
  7. struct Node {
  8. int key;
  9. bool color;
  10. Node * left;
  11. Node * right;
  12. Node * parent;
  13. Node(int k = , bool c = BLACK, Node *l = nullptr, Node *r = nullptr, Node *p = nullptr)
  14. : key(k), color(c), left(l), right(r), parent(p) {}
  15. };
  16. private :
  17. Node * nil;
  18. Node * root;
  19. private :
  20. void leftRotate(Node * x);
  21. void rightRotate(Node * x);
  22. void fixup_insert(Node * p);
  23. void fixup_remove(Node * p);
  24. void transplant(Node * old_t, Node * new_t);
  25. void insert(Node * p);
  26. void remove(Node * p);
  27. Node * search(Node * p, const int k);
  28. Node * minimum(Node * p);
  29. Node * maximum(Node * p);
  30. void inorderWalk(Node * p) const;
  31. public :
  32. RBT() : nil(new Node), root(nil) {}
  33. ~RBT() {delete nil;}
  34. void insert(const int key) {insert(new Node(key, RED, nil, nil, nil));}
  35. void remove(const int key) {remove(search(root, key));}
  36. bool search(const int key) {return (search(root, key) == nil ? false : true);}
  37. int minimum() {return minimum(root)->key;}
  38. int maximum() {return maximum(root)->key;}
  39. int predecessor(const int key);
  40. int successor(const int key);
  41.  
  42. friend ostream &operator<<(ostream &os, const RBT &t);
  43. };
  44.  
  45. void RBT::inorderWalk(Node * p) const {
  46. if (p != nil) {
  47. inorderWalk(p->left);
  48. cout << p->key << ' ';
  49. inorderWalk(p->right);
  50. }
  51. }
  52.  
  53. RBT::Node * RBT::search(Node * p, const int k) {
  54. if (p == nil || k == p->key)
  55. return p;
  56. if (k < p->key)
  57. return search(p->left, k);
  58. else
  59. return search(p->right, k);
  60. }
  61.  
  62. RBT::Node * RBT::minimum(Node * p) {
  63. if (p == nil)
  64. return p;
  65. while (p->left != nil)
  66. p = p->left;
  67. return p;
  68. }
  69.  
  70. RBT::Node * RBT::maximum(Node * p) {
  71. if (p == nil)
  72. return p;
  73. while (p->right != nil)
  74. p = p->right;
  75. return p;
  76. }
  77.  
  78. int RBT::predecessor(const int k) {
  79. Node * p = search(root, k);
  80. if (p == nil)
  81. return ;
  82. if (p->left != nil)
  83. return maximum(p->left)->key;
  84. Node * y = p->parent;
  85. while (y != nil && y->left == p) {
  86. p = y;
  87. y = y->parent;
  88. }
  89. return y->key;
  90. }
  91.  
  92. int RBT::successor(const int k) {
  93. Node * p = search(root, k);
  94. if (p == nil)
  95. return ;
  96. if (p->right != nil)
  97. return minimum(p->right)->key;
  98. Node * y = p->parent;
  99. while (y != nil && y->right == p) {
  100. p = y;
  101. y = y->parent;
  102. }
  103. return y->key;
  104. }
  105.  
  106. void RBT::leftRotate(Node * x) { //assume:x->right != nil
  107. Node * y = x->right;
  108. x->right = y->left;
  109. if (y->left != nil)
  110. y->left->parent = x;
  111. y->parent = x->parent;
  112. if (x->parent == nil)
  113. root = y;
  114. else if (x == x->parent->left)
  115. x->parent->left = y;
  116. else
  117. x->parent->right = y;
  118. y->left = x;
  119. x->parent = y;
  120. }
  121.  
  122. void RBT::rightRotate(Node * x) { //assume:x->left != nil
  123. Node * y = x->left;
  124. x->left = y->right;
  125. if (y->right != nil)
  126. y->right->parent = x;
  127. y->parent = x->parent;
  128. if (x->parent == nil)
  129. root = y;
  130. else if (x == x->parent->right)
  131. x->parent->right = y;
  132. else
  133. x->parent->left = y;
  134. y->right = x;
  135. x->parent = y;
  136. }
  137.  
  138. void RBT::insert(Node * p) {
  139. if (p == nullptr)
  140. return ;
  141. Node * x = root;
  142. Node * y = nil;
  143. while (x != nil) {
  144. y = x;
  145. if (x->key < p->key)
  146. x = x->right;
  147. else
  148. x = x->left;
  149. }
  150. p->parent = y;
  151. if (y == nil)
  152. root = p;
  153. else if (y->key < p->key)
  154. y->right = p;
  155. else
  156. y->left = p;
  157. fixup_insert(p);
  158. }
  159.  
  160. void RBT::fixup_insert(Node * p) {
  161. while (p->parent->color == RED) {
  162. if (p->parent == p->parent->parent->left) {
  163. Node * y = p->parent->parent->right;
  164. if (y->color == RED) { //case 1
  165. p->parent->color = BLACK;
  166. y->color = BLACK;
  167. p->parent->parent->color = RED;
  168. p = p->parent->parent;
  169. }
  170. else {
  171. if (p == p->parent->right) { //case 2
  172. p = p->parent;
  173. leftRotate(p);
  174. }
  175. p->parent->color = BLACK; //case 3
  176. p->parent->parent->color = RED;
  177. rightRotate(p->parent->parent);
  178. }
  179. }
  180. else { //with "right" and "left" exchanged
  181. Node * y = p->parent->parent->left;
  182. if (y->color == RED) { //case 1
  183. p->parent->color = BLACK;
  184. y->color = BLACK;
  185. p->parent->parent->color = RED;
  186. p = p->parent->parent;
  187. }
  188. else {
  189. if (p == p->parent->left) { //case 2
  190. p = p->parent;
  191. rightRotate(p);
  192. }
  193. p->parent->color = BLACK; //case 3
  194. p->parent->parent->color = RED;
  195. leftRotate(p->parent->parent);
  196. }
  197. }
  198. }
  199. root->color = BLACK;
  200. }
  201.  
  202. void RBT::transplant(Node * old_t, Node * new_t) {
  203. if (old_t->parent == nil)
  204. root = new_t;
  205. else if (old_t == old_t->parent->left)
  206. old_t->parent->left = new_t;
  207. else
  208. old_t->parent->right = new_t;
  209. new_t->parent = old_t->parent;
  210. }
  211.  
  212. void RBT::fixup_remove(Node * x) {
  213. Node * z = nil;
  214. while (x != root && x->color == BLACK) {
  215. if (x == x->parent->left) {
  216. z = x->parent->right;
  217. /*case 1*/ if (z->color == RED) {
  218. z->color = BLACK;
  219. x->parent->color = RED;
  220. leftRotate(x->parent);
  221. z = x->parent->right; //new z
  222. }
  223. /*case 2*/ if (z->left->color == BLACK && z->right->color == BLACK) {
  224. z->color = RED;
  225. x = x->parent;
  226. }
  227. else {
  228. /*case 3*/ if (z->right->color == BLACK) {
  229. z->left->color = BLACK;
  230. z->color = RED;
  231. rightRotate(z);
  232. z = x->parent->right;
  233. }
  234. /*case 4*/ z->color = x->parent->color;
  235. x->parent->color = BLACK;
  236. z->right->color = BLACK;
  237. leftRotate(x->parent);
  238. x = root; //exit while
  239. }
  240. }
  241. else {
  242. z = x->parent->left;
  243. /*case 1*/ if (z->color == RED) {
  244. z->color = BLACK;
  245. x->parent->color = RED;
  246. rightRotate(x->parent);
  247. z = x->parent->left; //new z
  248. }
  249. /*case 2*/ if (z->right->color == BLACK && z->left->color == BLACK) {
  250. z->color = RED;
  251. x = x->parent;
  252. }
  253. else {
  254. /*case 3*/ if (z->left->color == BLACK) {
  255. z->right->color = BLACK;
  256. z->color = RED;
  257. leftRotate(z);
  258. z = x->parent->left;
  259. }
  260. /*case 4*/ z->color = x->parent->color;
  261. x->parent->color = BLACK;
  262. z->left->color = BLACK;
  263. rightRotate(x->parent);
  264. x = root; //exit while
  265. }
  266. }
  267. }
  268. x->color = BLACK;
  269. }
  270.  
  271. void RBT::remove(Node * p) {
  272. if (p == nil)
  273. return ;
  274. Node * y = p;
  275. Node * x = nil;
  276. bool y_originalColor = y->color;
  277. if (p->left == nil) {
  278. x = p->right;
  279. transplant(p, p->right);
  280. }
  281. else if (p->right == nil) {
  282. x = p->left;
  283. transplant(p, p->left);
  284. }
  285. else {
  286. y = minimum(p->right);
  287. y_originalColor = y->color;
  288. x = y->right;
  289. if (y->parent == p)
  290. x->parent = y; //maybe x == nil
  291. else {
  292. transplant(y, y->right);
  293. y->right = p->right;
  294. y->right->parent = y;
  295. }
  296. transplant(p, y);
  297. y->left = p->left;
  298. y->left->parent = y;
  299. y->color = p->color;
  300. }
  301. delete p;
  302. if (y_originalColor == BLACK)
  303. fixup_remove(x);
  304. }
  305.  
  306. ostream &operator<<(ostream &os, const RBT &t) {
  307. t.inorderWalk(t.root);
  308. return os;
  309. }

RedBlack-Tree(红黑树)原理及C++代码实现的更多相关文章

  1. 红黑树原理详解及golang实现

    目录 红黑树原理详解及golang实现 二叉查找树 性质 红黑树 性质 operation 红黑树的插入 golang实现 类型定义 leftRotate RightRotate Item Inter ...

  2. Java面试题之红黑树原理

    红黑树原理: 每个节点都只能是红色或黑色的: 根节点是黑色的: 每个叶节点(空节点)是黑色的: 如果一个节点是红色的,那么他的子节点都是黑色的: 从任意一个节点到其每个子节点的路径都有相同数目的黑色节 ...

  3. Red Black Tree 红黑树 AVL trees 2-3 trees 2-3-4 trees B-trees Red-black trees Balanced search tree 平衡搜索树

    小结: 1.红黑树:典型的用途是实现关联数组 2.旋转 当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质.为了保持红黑树的性质,我们可以通过对树进行旋转,即修改树中某些 ...

  4. 从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树

    参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树) 目录 自平衡二叉树介绍 avl树 2-3树 LLRBT(Left-leaning red-black tree左倾红黑树 ...

  5. HashMap1.7和1.8,红黑树原理!

    jdk 1.7 概述 HashMap基于Map接口实现,元素以键值对的方式存储,并允许使用null键和null值,但只能有一个键作为null,因为key不允许重复,另外HashMap不能保证放入元素的 ...

  6. 排序二叉树、平衡二叉树、红黑树、B+树

    一.排序二叉树(Binary Sort Tree,BST树) 二叉排序树,又叫二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree). 1 ...

  7. AVL树、splay树(伸展树)和红黑树比较

    AVL树.splay树(伸展树)和红黑树比较 一.AVL树: 优点:查找.插入和删除,最坏复杂度均为O(logN).实现操作简单 如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实 ...

  8. 第十四章 红黑树——C++代码实现

    红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...

  9. 红黑树 - C++代码实现

    红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键 ...

  10. 红黑树插入与删除完整代码(dart语言实现)

    之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找.插入.删除等.删除后修复实现了两种算法,均比之前的更为简洁.一种是我自己的实现,代码非常简洁,行数更少:一种是Linux.Java等源码版 ...

随机推荐

  1. consul集群配置

    consul agent -server -bootstrap-expect 1 -data-dir /etc/consul -node=consul1 -bind=ip1 -ui -client=0 ...

  2. cf1208 D Restore Permutation (二分+树状数组)

    题意 让你构造一个长度为n的序列,记为p1……pn,(这个序列是1~n的全排列的一种) 给你n个数,记为s1……sn,si的值为p1……pi-1中小于pi的数的和. 思路 显然,应该倒着来,也就是从p ...

  3. python clickZan

    import pyautogui,time,random pyautogui.PAUSE = 3 pyautogui.FAILSAFE = True width, height = pyautogui ...

  4. 日志处理中一些shell命令技巧

    日志处理中一些shell命令技巧 阴差阳错的做的日志分析,前途未卜的这段日子,唯一还有点意思的可能就是手动的处理大量日志.总结一下. 日志文件的输入是动则几个G的文本.从N个这样的文件中得到一个列表, ...

  5. jenkins+saltstack+pipeline 部署springcloud 多模块jar包

    在jenkins上安装salt-master, pipeline{ agent{       node{               label 'master'               cust ...

  6. spring aop中的propagation的7种配置

    1.前言 在声明式的事务处理中,要配置一个切面,即一组方法,如 <tx:advice id="txAdvice" transaction-manager="txMa ...

  7. 18 11 13 装了ssd 继续 网络通信 tcp 客户端的创建

    import socket def main(): # 1. 买个手机(创建套接字 socket) 联通公司建立了一个信号塔 tcp_server_socket = socket.socket(soc ...

  8. CENTOS YUM更新源

    网络yum源和制作本地光盘yum源 配置CENTOS YUM更新源 yum安装rpm包安装后本地不清除的方法 sed -i 's#keepcache=0#keepcache=1#g' /etc/yum ...

  9. ubuntu下git的使用

    1.安装git sudo apt-get install git sudo apt-get install git-core 2.配置git lzb@lzb:~$ git config --globa ...

  10. Scala(一)——scala+Idea环境配置

    Java虚拟机的确是很强大,有很多计算机语言可以运行在虚拟机上,完善了虚拟机上多语言编程. 近年来,大数据云计算,大数据的火爆也让一些小众语言火了起来,如Python,Scala等.这些语言编写简单, ...