首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

红黑树的C实现完整源码

  • 25-03-02 16:41
  • 2704
  • 13099
blog.csdn.net

红黑树C源码实现与剖析

作者:July 、那谁   时间:二零一一年一月三日

-------------------------

前言:
    红黑树作为一种经典而高级的数据结构,相信,已经被不少人实现过,但不是因为程序不够完善而无法运行,就是因为程序完全没有注释,初学者根本就看不懂。
    此份红黑树的c源码最初从linux-lib-rbtree.c而来,后经一网友那谁(http://www.cppblog.com/converse/)用c写了出来。在此,向原作者表示敬意。

    考虑到原来的程序没有注释,所以我特把这份源码放到编译器里,一行一行的完善,一行一行的给它添加注释,至此,红黑树c带注释的源码,就摆在了您眼前,有不妥、不正之处,还望不吝指正。
------------

红黑树的六篇文章:

1、教你透彻了解红黑树
2、红黑树算法的实现与剖析
3、红黑树的c源码实现与剖析
4、一步一图一代码,R-B Tree
5、红黑树插入和删除结点的全程演示
6、红黑树的c++完整实现源码

-------------------------

ok,咱们开始吧。
    相信,经过我前俩篇博文对红黑树的介绍,你应该对红黑树有了透彻的理解了(没看过的朋友,可事先查上面的倆篇文章,或与此文的源码剖析对应着看)。

    本套源码剖析把重点放在红黑树的3种插入情况,与红黑树的4种删除情况。其余的能从略则尽量简略。

目录:
一、左旋代码分析
二、右旋
三、红黑树查找结点
四、红黑树的插入
五、红黑树的3种插入情况
六、红黑树的删除
七、红黑树的4种删除情况
八、测试用例

好的,咱们还是先从树的左旋、右旋代码,开始(大部分分析,直接给注释):

  1. //一、左旋代码分析
  2. /*-----------------------------------------------------------
  3. | node right
  4. | / / ==> / /
  5. | a right node y
  6. | / / / /
  7. | b y a b //左旋
  8. -----------------------------------------------------------*/
  9. static rb_node_t* rb_rotate_left(rb_node_t* node, rb_node_t* root)
  10. {
  11. rb_node_t* right = node->right; //指定指针指向 right<--node->right
  12. if ((node->right = right->left))
  13. {
  14. right->left->parent = node; //好比上面的注释图,node成为b的父母
  15. }
  16. right->left = node; //node成为right的左孩子
  17. if ((right->parent = node->parent))
  18. {
  19. if (node == node->parent->right)
  20. {
  21. node->parent->right = right;
  22. }
  23. else
  24. {
  25. node->parent->left = right;
  26. }
  27. }
  28. else
  29. {
  30. root = right;
  31. }
  32. node->parent = right; //right成为node的父母
  33. return root;
  34. }
  35. //二、右旋
  36. /*-----------------------------------------------------------
  37. | node left
  38. | / / / /
  39. | left y ==> a node
  40. | / / / /
  41. | a b b y //右旋与左旋差不多,分析略过
  42. -----------------------------------------------------------*/
  43. static rb_node_t* rb_rotate_right(rb_node_t* node, rb_node_t* root)
  44. {
  45. rb_node_t* left = node->left;
  46. if ((node->left = left->right))
  47. {
  48. left->right->parent = node;
  49. }
  50. left->right = node;
  51. if ((left->parent = node->parent))
  52. {
  53. if (node == node->parent->right)
  54. {
  55. node->parent->right = left;
  56. }
  57. else
  58. {
  59. node->parent->left = left;
  60. }
  61. }
  62. else
  63. {
  64. root = left;
  65. }
  66. node->parent = left;
  67. return root;
  68. }
  69. //三、红黑树查找结点
  70. //----------------------------------------------------
  71. //rb_search_auxiliary:查找
  72. //rb_node_t* rb_search:返回找到的结点
  73. //----------------------------------------------------
  74. static rb_node_t* rb_search_auxiliary(key_t key, rb_node_t* root, rb_node_t** save)
  75. {
  76. rb_node_t *node = root, *parent = NULL;
  77. int ret;
  78. while (node)
  79. {
  80. parent = node;
  81. ret = node->key - key;
  82. if (0 < ret)
  83. {
  84. node = node->left;
  85. }
  86. else if (0 > ret)
  87. {
  88. node = node->right;
  89. }
  90. else
  91. {
  92. return node;
  93. }
  94. }
  95. if (save)
  96. {
  97. *save = parent;
  98. }
  99. return NULL;
  100. }
  101. //返回上述rb_search_auxiliary查找结果
  102. rb_node_t* rb_search(key_t key, rb_node_t* root)
  103. {
  104. return rb_search_auxiliary(key, root, NULL);
  105. }
  106. //四、红黑树的插入
  107. //---------------------------------------------------------
  108. //红黑树的插入结点
  109. rb_node_t* rb_insert(key_t key, data_t data, rb_node_t* root)
  110. {
  111. rb_node_t *parent = NULL, *node;
  112. parent = NULL;
  113. if ((node = rb_search_auxiliary(key, root, &parent))) //调用rb_search_auxiliary找到插入结
  114. 点的地方
  115. {
  116. return root;
  117. }
  118. node = rb_new_node(key, data); //分配结点
  119. node->parent = parent;
  120. node->left = node->right = NULL;
  121. node->color = RED;
  122. if (parent)
  123. {
  124. if (parent->key > key)
  125. {
  126. parent->left = node;
  127. }
  128. else
  129. {
  130. parent->right = node;
  131. }
  132. }
  133. else
  134. {
  135. root = node;
  136. }
  137. return rb_insert_rebalance(node, root); //插入结点后,调用rb_insert_rebalance修复红黑树
  138. 的性质
  139. }
  140. //五、红黑树的3种插入情况
  141. //接下来,咱们重点分析针对红黑树插入的3种情况,而进行的修复工作。
  142. //--------------------------------------------------------------
  143. //红黑树修复插入的3种情况
  144. //为了在下面的注释中表示方便,也为了让下述代码与我的倆篇文章相对应,
  145. //用z表示当前结点,p[z]表示父母、p[p[z]]表示祖父、y表示叔叔。
  146. //--------------------------------------------------------------
  147. static rb_node_t* rb_insert_rebalance(rb_node_t *node, rb_node_t *root)
  148. {
  149. rb_node_t *parent, *gparent, *uncle, *tmp; //父母p[z]、祖父p[p[z]]、叔叔y、临时结点*tmp
  150. while ((parent = node->parent) && parent->color == RED)
  151. { //parent 为node的父母,且当父母的颜色为红时
  152. gparent = parent->parent; //gparent为祖父
  153. if (parent == gparent->left) //当祖父的左孩子即为父母时。
  154. //其实上述几行语句,无非就是理顺孩子、父母、祖父的关系。:D。
  155. {
  156. uncle = gparent->right; //定义叔叔的概念,叔叔y就是父母的右孩子。
  157. if (uncle && uncle->color == RED) //情况1:z的叔叔y是红色的
  158. {
  159. uncle->color = BLACK; //将叔叔结点y着为黑色
  160. parent->color = BLACK; //z的父母p[z]也着为黑色。解决z,p[z]都是红色的问题。
  161. gparent->color = RED;
  162. node = gparent; //将祖父当做新增结点z,指针z上移俩层,且着为红色。
  163. //上述情况1中,只考虑了z作为父母的右孩子的情况。
  164. }
  165. else //情况2:z的叔叔y是黑色的,
  166. {
  167. if (parent->right == node) //且z为右孩子
  168. {
  169. root = rb_rotate_left(parent, root); //左旋[结点z,与父母结点]
  170. tmp = parent;
  171. parent = node;
  172. node = tmp; //parent与node 互换角色
  173. }
  174. //情况3:z的叔叔y是黑色的,此时z成为了左孩子。
  175. //注意,1:情况3是由上述情况2变化而来的。
  176. //......2:z的叔叔总是黑色的,否则就是情况1了。
  177. parent->color = BLACK; //z的父母p[z]着为黑色
  178. gparent->color = RED; //原祖父结点着为红色
  179. root = rb_rotate_right(gparent, root); //右旋[结点z,与祖父结点]
  180. }
  181. }
  182. else
  183. {
  184. // if (parent == gparent->right) 当祖父的右孩子即为父母时。(解释请看本文评论下第23楼,同时,感谢SupremeHover指正!)
  185. uncle = gparent->left; //祖父的左孩子作为叔叔结点。[原理还是与上部分一样的]
  186. if (uncle && uncle->color == RED) //情况1:z的叔叔y是红色的
  187. {
  188. uncle->color = BLACK;
  189. parent->color = BLACK;
  190. gparent->color = RED;
  191. node = gparent; //同上。
  192. }
  193. else //情况2:z的叔叔y是黑色的,
  194. {
  195. if (parent->left == node) //且z为左孩子
  196. {
  197. root = rb_rotate_right(parent, root); //以结点parent、root右旋
  198. tmp = parent;
  199. parent = node;
  200. node = tmp; //parent与node 互换角色
  201. }
  202. //经过情况2的变化,成为了情况3.
  203. parent->color = BLACK;
  204. gparent->color = RED;
  205. root = rb_rotate_left(gparent, root); //以结点gparent和root左旋
  206. }
  207. }
  208. }
  209. root->color = BLACK; //根结点,不论怎样,都得置为黑色。
  210. return root; //返回根结点。
  211. }
  212. //六、红黑树的删除
  213. //------------------------------------------------------------
  214. //红黑树的删除结点
  215. rb_node_t* rb_erase(key_t key, rb_node_t *root)
  216. {
  217. rb_node_t *child, *parent, *old, *left, *node;
  218. color_t color;
  219. if (!(node = rb_search_auxiliary(key, root, NULL))) //调用rb_search_auxiliary查找要删除的
  220. 结点
  221. {
  222. printf("key %d is not exist!/n");
  223. return root;
  224. }
  225. old = node;
  226. if (node->left && node->right)
  227. {
  228. node = node->right;
  229. while ((left = node->left) != NULL)
  230. {
  231. node = left;
  232. }
  233. child = node->right;
  234. parent = node->parent;
  235. color = node->color;
  236. if (child)
  237. {
  238. child->parent = parent;
  239. }
  240. if (parent)
  241. {
  242. if (parent->left == node)
  243. {
  244. parent->left = child;
  245. }
  246. else
  247. {
  248. parent->right = child;
  249. }
  250. }
  251. else
  252. {
  253. root = child;
  254. }
  255. if (node->parent == old)
  256. {
  257. parent = node;
  258. }
  259. node->parent = old->parent;
  260. node->color = old->color;
  261. node->right = old->right;
  262. node->left = old->left;
  263. if (old->parent)
  264. {
  265. if (old->parent->left == old)
  266. {
  267. old->parent->left = node;
  268. }
  269. else
  270. {
  271. old->parent->right = node;
  272. }
  273. }
  274. else
  275. {
  276. root = node;
  277. }
  278. old->left->parent = node;
  279. if (old->right)
  280. {
  281. old->right->parent = node;
  282. }
  283. }
  284. else
  285. {
  286. if (!node->left)
  287. {
  288. child = node->right;
  289. }
  290. else if (!node->right)
  291. {
  292. child = node->left;
  293. }
  294. parent = node->parent;
  295. color = node->color;
  296. if (child)
  297. {
  298. child->parent = parent;
  299. }
  300. if (parent)
  301. {
  302. if (parent->left == node)
  303. {
  304. parent->left = child;
  305. }
  306. else
  307. {
  308. parent->right = child;
  309. }
  310. }
  311. else
  312. {
  313. root = child;
  314. }
  315. }
  316. free(old);
  317. if (color == BLACK)
  318. {
  319. root = rb_erase_rebalance(child, parent, root); //调用rb_erase_rebalance来恢复红黑树性
  320. 质
  321. }
  322. return root;
  323. }
  324. //七、红黑树的4种删除情况
  325. //----------------------------------------------------------------
  326. //红黑树修复删除的4种情况
  327. //为了表示下述注释的方便,也为了让下述代码与我的倆篇文章相对应,
  328. //x表示要删除的结点,*other、w表示兄弟结点,
  329. //----------------------------------------------------------------
  330. static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
  331. {
  332. rb_node_t *other, *o_left, *o_right; //x的兄弟*other,兄弟左孩子*o_left,*o_right
  333. while ((!node || node->color == BLACK) && node != root)
  334. {
  335. if (parent->left == node)
  336. {
  337. other = parent->right;
  338. if (other->color == RED) //情况1:x的兄弟w是红色的
  339. {
  340. other->color = BLACK;
  341. parent->color = RED; //上俩行,改变颜色,w->黑、p[x]->红。
  342. root = rb_rotate_left(parent, root); //再对p[x]做一次左旋
  343. other = parent->right; //x的新兄弟new w 是旋转之前w的某个孩子。其实就是左旋后
  344. 的效果。
  345. }
  346. if ((!other->left || other->left->color == BLACK) &&
  347. (!other->right || other->right->color == BLACK))
  348. //情况2:x的兄弟w是黑色,且w的俩个孩子也
  349. 都是黑色的
  350. { //由于w和w的俩个孩子都是黑色的,则在x和w上得去掉一黑色,
  351. other->color = RED; //于是,兄弟w变为红色。
  352. node = parent; //p[x]为新结点x
  353. parent = node->parent; //x<-p[x]
  354. }
  355. else //情况3:x的兄弟w是黑色的,
  356. { //且,w的左孩子是红色,右孩子为黑色。
  357. if (!other->right || other->right->color == BLACK)
  358. {
  359. if ((o_left = other->left)) //w和其左孩子left[w],颜色交换。
  360. {
  361. o_left->color = BLACK; //w的左孩子变为由黑->红色
  362. }
  363. other->color = RED; //w由黑->红
  364. root = rb_rotate_right(other, root); //再对w进行右旋,从而红黑性质恢复。
  365. other = parent->right; //变化后的,父结点的右孩子,作为新的兄弟结点
  366. w。
  367. }
  368. //情况4:x的兄弟w是黑色的
  369. other->color = parent->color; //把兄弟节点染成当前节点父节点的颜色。
  370. parent->color = BLACK; //把当前节点父节点染成黑色
  371. if (other->right) //且w的右孩子是红
  372. {
  373. other->right->color = BLACK; //兄弟节点w右孩子染成黑色
  374. }
  375. root = rb_rotate_left(parent, root); //并再做一次左旋
  376. node = root; //并把x置为根。
  377. break;
  378. }
  379. }
  380. //下述情况与上述情况,原理一致。分析略。
  381. else
  382. {
  383. other = parent->left;
  384. if (other->color == RED)
  385. {
  386. other->color = BLACK;
  387. parent->color = RED;
  388. root = rb_rotate_right(parent, root);
  389. other = parent->left;
  390. }
  391. if ((!other->left || other->left->color == BLACK) &&
  392. (!other->right || other->right->color == BLACK))
  393. {
  394. other->color = RED;
  395. node = parent;
  396. parent = node->parent;
  397. }
  398. else
  399. {
  400. if (!other->left || other->left->color == BLACK)
  401. {
  402. if ((o_right = other->right))
  403. {
  404. o_right->color = BLACK;
  405. }
  406. other->color = RED;
  407. root = rb_rotate_left(other, root);
  408. other = parent->left;
  409. }
  410. other->color = parent->color;
  411. parent->color = BLACK;
  412. if (other->left)
  413. {
  414. other->left->color = BLACK;
  415. }
  416. root = rb_rotate_right(parent, root);
  417. node = root;
  418. break;
  419. }
  420. }
  421. }
  422. if (node)
  423. {
  424. node->color = BLACK; //最后将node[上述步骤置为了根结点],改为黑色。
  425. }
  426. return root; //返回root
  427. }
  428. //八、测试用例
  429. //主函数
  430. int main()
  431. {
  432. int i, count = 100;
  433. key_t key;
  434. rb_node_t* root = NULL, *node = NULL;
  435. srand(time(NULL));
  436. for (i = 1; i < count; ++i)
  437. {
  438. key = rand() % count;
  439. if ((root = rb_insert(key, i, root)))
  440. {
  441. printf("[i = %d] insert key %d success!/n", i, key);
  442. }
  443. else
  444. {
  445. printf("[i = %d] insert key %d error!/n", i, key);
  446. exit(-1);
  447. }
  448. if ((node = rb_search(key, root)))
  449. {
  450. printf("[i = %d] search key %d success!/n", i, key);
  451. }
  452. else
  453. {
  454. printf("[i = %d] search key %d error!/n", i, key);
  455. exit(-1);
  456. }
  457. if (!(i % 10))
  458. {
  459. if ((root = rb_erase(key, root)))
  460. {
  461. printf("[i = %d] erase key %d success/n", i, key);
  462. }
  463. else
  464. {
  465. printf("[i = %d] erase key %d error/n", i, key);
  466. }
  467. }
  468. }
  469. return 0;
  470. }

ok,完。

后记:

一、欢迎任何人就此份源码,以及我的前述倆篇文章,进行讨论、提议。
但任何人,引用此份源码剖析,必须得注明作者本人July以及出处。
红黑树系列,已经写了三篇文章,相信,教你透彻了解红黑树的目的,应该达到了。
二、本文完整源码,请到此处下载:

http://download.csdn.net/source/2958890

1、教你透彻了解红黑树
2、红黑树算法的实现与剖析
3、红黑树的c源码实现与剖析
4、一步一图一代码,R-B Tree
5、红黑树插入和删除结点的全程演示
6、红黑树的c++完整实现源码

 转载本BLOG内任何文章,请以超链接形式注明出处。非常感谢。

文章知识点与官方知识档案匹配,可进一步学习相关知识
C技能树首页概览156674 人正在系统学习中
注:本文转载自blog.csdn.net的v_JULY_v的文章"http://blog.csdn.net/v_JULY_v/archive/2011/01/03/6114226.aspx"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top