免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: converse
打印 上一主题 下一主题

[算法] <<算法导论>>一起学之二:红黑树的实现C源码 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2006-03-21 23:38 |只看该作者
原帖由 win_hate 于 2006-3-21 23:33 发表
>> 2) 根结点是黑色的

这个观点好象很可疑.......

书上:



第13章才是讲的红黑树的吧?这个第二个是红黑树的性质之一呀,没明白老大的问题是什么

论坛徽章:
0
12 [报告]
发表于 2006-03-22 10:06 |只看该作者
根节点的颜色是黑色的, 红色的, 不要求的?  以前我也遇到这个问题, 查了Weiss的书, 黑色; ULK2, 黑色; Algorithms没说。 P.S. Linux内核的virtual memory area, 同一个进程的, 是通过rbtree组织到一起的(2.4.9以后的都是), 代码实现在mm/mmap.c中。

论坛徽章:
0
13 [报告]
发表于 2006-03-22 10:19 |只看该作者
原帖由 albcamus 于 2006-3-22 10:06 发表
根节点的颜色是黑色的, 红色的, 不要求的?  以前我也遇到这个问题, 查了Weiss的书, 黑色; ULK2, 黑色; Algorithms没说。 P.S. Linux内核的virtual memory area, 同一个进程的, 是通过rbtree组织到一起的 ...


昨晚跟win_hate老大聊了,确定了在算法导论第一版中确实没有要求root是黑色的,里面红黑树的性质只有4个,网上流传很广的算法导论中文版也是第一版的翻译,哪位手头有的可以看看,里面确实是只有4个性质.对此我也很是好奇,但是没有再仔细的看里面的实现了,红黑树是我遇到的最为复杂的一种数据结构了,头大了,不想继续深究下去了

论坛徽章:
0
14 [报告]
发表于 2006-03-22 10:22 |只看该作者
另:很多书包括很多经典的数据结构算法书都没有讲述到红黑树的删除节点操作,比如Weiss的和Algorithms,我现在手头三本书都有,算法导论为主,看到实现的地方不明白的就参考这两本书,可就是这个删除算法,因为没有可以参考的,花费了我一个礼拜的时间去找资料和写算法加调试

论坛徽章:
0
15 [报告]
发表于 2006-03-22 11:13 |只看该作者
原帖由 albcamus 于 2006-3-22 10:06 发表
P.S. Linux内核的virtual memory area, 同一个进程的, 是通过rbtree组织到一起的(2.4.9以后的都是), 代码实现在mm/mmap.c中。 ...

Linux中是用vm_area_struct结构体来描述一段连续的内存区域的,FreeBSD中与此对应的结构体是vm_map_entry。两者的共同点是,都同时使用两种数据结构来组织这些结构体,一种是链表,一种是树,只不过FreeBSD是用splay树来组织vm_map_entry结构体的。我前两天做了点FreeBSD的splay树相关代码的分析:

【FreeBSD虚存系统splay树的基本原理】

【FreeBSD虚存系统splay树的代码分析】

等我把这边的代码分析做完了,就和Linux的红黑树比较一下。
另外,NetBSD里面好像使用的也是红黑树。

论坛徽章:
0
16 [报告]
发表于 2006-03-22 11:23 |只看该作者

回复 15楼 雨丝风片 的帖子

哈, 好~那我也回去看一下,到时比较下(linux的2.4.9以前用的是AVL树^_^)

论坛徽章:
0
17 [报告]
发表于 2006-03-22 11:28 |只看该作者
原帖由 albcamus 于 2006-3-22 11:23 发表
哈, 好~那我也回去看一下,到时比较下(linux的2.4.9以前用的是AVL树^_^)


嗯,ULK2有云:
Up to Version 2.4.9, the Linux kernel used another type of balanced search tree called AVL tree.


看来各个系统都在来回折腾寻找更好的算法,这样就更有互相比较借鉴的必要了,

论坛徽章:
0
18 [报告]
发表于 2007-07-29 09:56 |只看该作者
不知道红黑树到底有什么优势,在算法上插入删除更复杂

论坛徽章:
0
19 [报告]
发表于 2007-07-29 10:53 |只看该作者
查找很快,虽然平时复杂了点。
就像操作系统的调度,如果有了一个新进程直接插一个链表很简单,但是调度的时候决定谁该运行就费时了。 所有就有多种优先级链表。
就好比平时如果不复习,考试的前几天就得熬夜^^

论坛徽章:
0
20 [报告]
发表于 2007-11-28 14:32 |只看该作者
这份代码是有问题的,修正的在这里:


  1. /*-----------------------------------------------------------
  2.         RB-Tree的插入和删除操作的实现算法
  3.         参考资料:
  4.         1) <<Introduction to algorithm>>
  5.         2) <<STL源码剖析>>
  6.         3) sgi-stl中stl_tree.h中的实现算法
  7.         4) [url]http://epaperpress.com/sortsearch/index.html[/url]
  8.         5) [url]http://www.ececs.uc.edu/~franco/C321/html/RedBlack/redblack.html[/url]

  9.         作者:李创 ([url]http://www.cppblog.com/converse/[/url])
  10.         您可以自由的传播,修改这份代码,转载处请注明原作者

  11.         红黑树的几个性质:
  12.         1) 每个结点只有红和黑两种颜色
  13.         2) 根结点是黑色的
  14.         3)空节点是黑色的(红黑树中,根节点的parent以及所有叶节点lchild、rchild都不指向NULL,而是指向一个定义好的空节点)。
  15.         4) 如果一个结点是红色的,那么它的左右两个子结点的颜色是黑色的
  16.         5) 对于每个结点而言,从这个结点到叶子结点的任何路径上的黑色结点
  17.         的数目相同
  18. -------------------------------------------------------------*/

  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <time.h>

  22. typedef int KEY;

  23. enum NODECOLOR
  24. {
  25.         BLACK        = 0,
  26.         RED          = 1
  27. };

  28. typedef struct RBTree
  29. {
  30.         struct                RBTree *parent;
  31.         struct      RBTree *left, *right;
  32.         KEY                        key;
  33.         NODECOLOR   color;
  34. }RBTree, *PRBTree;

  35. PRBTree RB_InsertNode(PRBTree root, KEY key);
  36. PRBTree RB_InsertNode_Fixup(PRBTree root, PRBTree z);

  37. PRBTree RB_DeleteNode(PRBTree root, KEY key);
  38. PRBTree RB_DeleteNode_Fixup(PRBTree root, PRBTree x , PRBTree x_parent);

  39. PRBTree Find_Node(PRBTree root, KEY key);
  40. void    Left_Rotate(PRBTree A, PRBTree& root);
  41. void    Right_Rotate(PRBTree A, PRBTree& root);
  42. void    Mid_Visit(PRBTree T);
  43. void    Mid_DeleteTree(PRBTree T);
  44. void    Print_Node(PRBTree node);

  45. /*-----------------------------------------------------------
  46. |   A              B
  47. |  / \    ==>     / \
  48. | a   B           A  y
  49. |    / \         / \
  50. |    b  y        a  b
  51. -----------------------------------------------------------*/
  52. void Left_Rotate(PRBTree A, PRBTree& root)
  53. {      
  54.         PRBTree B;
  55.         B = A->right;

  56.         A->right  = B->left;
  57.         if (NULL != B->left)
  58.                 B->left->parent = A;
  59.         B->parent = A->parent;

  60.         // 这样三个判断连在一起避免了A->parent = NULL的情况
  61.         if (A == root)
  62.         {
  63.                 root = B;
  64.         }
  65.         else if (A == A->parent->left)
  66.         {
  67.                 A->parent->left = B;
  68.         }
  69.         else
  70.         {
  71.                 A->parent->right = B;
  72.         }
  73.         B->left          = A;
  74.         A->parent = B;
  75. }

  76. /*-----------------------------------------------------------
  77. |    A              B
  78. |   / \            / \
  79. |  B   y   ==>    a   A
  80. | / \                / \
  81. |a   b              b   y
  82. -----------------------------------------------------------*/
  83. void Right_Rotate(PRBTree A, PRBTree& root)
  84. {
  85.         PRBTree B;
  86.         B = A->left;

  87.         A->left   = B->right;
  88.         if (NULL != B->right)
  89.                 B->right->parent = A;

  90.         B->parent = A->parent;
  91.         // 这样三个判断连在一起避免了A->parent = NULL的情况
  92.         if (A == root)
  93.         {
  94.                 root = B;
  95.         }
  96.         else if (A == A->parent->left)
  97.         {
  98.                 A->parent->left = B;
  99.         }
  100.         else
  101.         {
  102.                 A->parent->right = B;
  103.         }
  104.         A->parent = B;
  105.         B->right  = A;
  106. }

  107. /*-----------------------------------------------------------
  108. |        函数作用:查找key值对应的结点指针
  109. |        输入参数:根节点root,待查找关键值key
  110. |        返回参数:如果找到返回结点指针,否则返回NULL
  111. -------------------------------------------------------------*/
  112. PRBTree Find_Node(PRBTree root, KEY key)
  113. {
  114.         PRBTree x;

  115.         // 找到key所在的node
  116.         x = root;
  117.         do
  118.         {
  119.                 if (key == x->key)
  120.                         break;
  121.                 if (key < x->key)
  122.                 {
  123.                         if (NULL != x->left)
  124.                                 x = x->left;
  125.                         else
  126.                                 break;
  127.                 }
  128.                 else
  129.                 {
  130.                         if (NULL != x->right)
  131.                                 x = x->right;
  132.                         else
  133.                                 break;
  134.                 }
  135.         } while (NULL != x);

  136.         return x;
  137. }

  138. /*-----------------------------------------------------------
  139. |        函数作用:在树中插入key值
  140. |        输入参数:根节点root,待插入结点的关键值key
  141. |        返回参数:根节点root
  142. -------------------------------------------------------------*/
  143. PRBTree RB_InsertNode(PRBTree root, KEY key)
  144. {
  145.         PRBTree x, y;

  146.         PRBTree z;
  147.         if (NULL == (z = (PRBTree)malloc(sizeof(RBTree))))
  148.         {
  149.                 printf("Memory alloc error\n");
  150.                 return NULL;
  151.         }
  152.         z->key = key;

  153.         // 得到z的父节点, 如果KEY已经存在就直接返回
  154.         x = root, y = NULL;
  155.         while (NULL != x)
  156.         {
  157.                 y = x;
  158.                 if (key < x->key)
  159.                 {
  160.                         if (NULL != x->left)
  161.                         {
  162.                                 x = x->left;
  163.                         }
  164.                         else
  165.                         {
  166.                                 break;
  167.                         }
  168.                 }
  169.                 else if (key > x->key)
  170.                 {
  171.                         if (NULL != x->right)
  172.                         {
  173.                                 x = x->right;
  174.                         }
  175.                         else
  176.                         {
  177.                                 break;
  178.                         }
  179.                 }
  180.         else
  181.         {
  182.             return root;   
  183.         }
  184.         }

  185.     if (NULL == y || y->key > key)
  186.     {
  187.         if (NULL == y)
  188.             root = z;
  189.         else
  190.             y->left = z;
  191.     }
  192.     else
  193.     {
  194.         y->right = z;
  195.     }

  196.         // 设置z的左右子树为空并且颜色是red,注意新插入的节点颜色都是red
  197.     z->parent = y;   
  198.         z->left = z->right = NULL;
  199.         z->color = RED;

  200.         // 对红黑树进行修正
  201.         return RB_InsertNode_Fixup(root, z);
  202. }

  203. /*-----------------------------------------------------------
  204. |        函数作用:对插入key值之后的树进行修正
  205. |        输入参数:根节点root,插入的结点z
  206. |        返回参数:根节点root
  207. -------------------------------------------------------------*/
  208. PRBTree RB_InsertNode_Fixup(PRBTree root, PRBTree z)
  209. {
  210.         PRBTree y;
  211.         while (root != z && RED == z->parent->color)        // 当z不是根同时父节点的颜色是red
  212.         {
  213.                 if (z->parent == z->parent->parent->left)        // 父节点是祖父节点的左子树
  214.                 {
  215.                         y = z->parent->parent->right;                        // y为z的伯父节点
  216.                         if (NULL != y && RED == y->color)                // 伯父节点存在且颜色是red
  217.                         {
  218.                                 z->parent->color = BLACK;                        // 更改z的父节点颜色是B
  219.                                 y->color = BLACK;                                        // 更改z的伯父节点颜色是B
  220.                                 z->parent->parent->color = RED;                // 更改z的祖父节点颜色是B
  221.                                 z = z->parent->parent;                                // 更新z为它的祖父节点
  222.                         }
  223.                         else                                                                        // 无伯父节点或者伯父节点颜色是b
  224.                         {
  225.                                 if (z == z->parent->right)                        // 如果新节点是父节点的右子树
  226.                                 {
  227.                                         z = z->parent;
  228.                                         Left_Rotate(z, root);
  229.                                 }
  230.                                 z->parent->color = BLACK;                        // 改变父节点颜色是B
  231.                                 z->parent->parent->color = RED;                // 改变祖父节点颜色是R
  232.                                 Right_Rotate(z->parent->parent, root);
  233.                         }
  234.                 }
  235.                 else                                                                                // 父节点为祖父节点的右子树
  236.                 {
  237.                         y = z->parent->parent->left;                        // y为z的伯父节点
  238.                         if (NULL != y && RED == y->color)                // 如果y的颜色是red
  239.                         {
  240.                                 z->parent->color = BLACK;                        // 更改父节点的颜色为B
  241.                                 y->color = BLACK;                                        // 更改伯父节点的颜色是B
  242.                                 z->parent->parent->color = RED;                // 更改祖父节点颜色是R
  243.                                 z = z->parent->parent;                                // 更改z指向祖父节点
  244.                         }               
  245.                         else                                                                        // y不存在或者颜色是B
  246.                         {
  247.                                 if (z == z->parent->left)                        // 如果是父节点的左子树
  248.                                 {
  249.                                         z = z->parent;
  250.                                         Right_Rotate(z, root);
  251.                                 }
  252.                                 z->parent->color = BLACK;                        // 改变父节点的颜色是B
  253.                                 z->parent->parent->color = RED;                // 改变祖父节点的颜色是RED
  254.                                 Left_Rotate(z->parent->parent, root);
  255.                         }
  256.                 }
  257.         } // while(RED == z->parent->color)

  258.         // 根节点的颜色始终都是B
  259.         root->color = BLACK;

  260.         return root;
  261. }

  262. /*-----------------------------------------------------------
  263. |        函数作用:在树中删除key值
  264. |        输入参数:根节点root,待插入结点的关键值key
  265. |        返回参数:根节点root
  266. -------------------------------------------------------------*/
  267. PRBTree RB_DeleteNode(PRBTree root, KEY key)
  268. {
  269.         PRBTree x, y, z, x_parent;

  270.     // 首先查找需要删除的节点
  271.         z = Find_Node(root, key);
  272.         if (NULL == z)
  273.                 return root;

  274.     y = z, x = NULL, x_parent = NULL;

  275.         // y是x按照中序遍历树的后继
  276.     if (NULL == y->left)
  277.     {
  278.         x = y->right;
  279.     }
  280.     else
  281.     {
  282.         if (NULL == y->right)
  283.         {
  284.             x = y->left;
  285.         }
  286.         else
  287.         {
  288.             y = y->right;
  289.             while (NULL != y->left)
  290.                 y = y->left;
  291.             x = y->right;
  292.         }
  293.     }

  294.     if (y != z)
  295.     {
  296.         z->left->parent = y;
  297.         y->left = z->left;
  298.         if (y != z->right)
  299.         {
  300.             x_parent = y->parent;
  301.             if (NULL != x)
  302.                 x->parent = y->parent;
  303.             y->parent->left = x;
  304.             y->right = z->right;
  305.             z->right->parent = y;
  306.         }
  307.         else
  308.         {
  309.             x_parent = y;
  310.         }
  311.         if (root == z)
  312.         {
  313.             root = y;
  314.         }
  315.         else if (z == z->parent->left)
  316.         {
  317.             z->parent->left = y;
  318.         }
  319.         else
  320.         {
  321.             z->parent->right = y;
  322.         }
  323.         y->parent = z->parent;
  324.         NODECOLOR color = y->color;
  325.         y->color = z->color;
  326.         z->color = color;
  327.         y = z;
  328.     }
  329.     else
  330.     {
  331.         x_parent = y->parent;
  332.         if (NULL != x)
  333.             x->parent = y->parent;
  334.         if (root == z)
  335.         {
  336.             root = y;
  337.         }
  338.         else if (z == z->parent->left)
  339.         {
  340.             z->parent->left = x;
  341.         }
  342.         else
  343.         {
  344.             z->parent->right = x;
  345.         }

  346.     }

  347.     if (BLACK == y->color)
  348.     {
  349.         root = RB_DeleteNode_Fixup(root, x, x_parent);
  350.     }
  351.         free(y);

  352.         return root;
  353. }

  354. /*-----------------------------------------------------------
  355. |        函数作用:对删除key值之后的树进行修正
  356. |        输入参数:根节点root,删除的结点的子结点x
  357. |        返回参数:根节点root
  358. -------------------------------------------------------------*/
  359. PRBTree RB_DeleteNode_Fixup(PRBTree root, PRBTree x, PRBTree x_parent)
  360. {
  361.         PRBTree w;

  362.         while (x != root && BLACK == x->color)
  363.         {
  364.                 if (x == x_parent->left)                                                                // 如果x是左子树
  365.                 {
  366.                         w = x_parent->right;                                                                // w是x的兄弟结点
  367.                         if (RED == w->color)                                                                // 如果w的颜色是红色
  368.                         {
  369.                                 w->color = BLACK;
  370.                                 x_parent->color = RED;
  371.                                 Left_Rotate(x_parent, root);
  372.                                 w = x_parent->right;
  373.                         }
  374.                         if ((NULL == w->left  || BLACK == w->left->color) &&
  375.                                 (NULL == w->right || BLACK == w->right->color))
  376.                         {
  377.                                 w->color = RED;
  378.                 x = x_parent;
  379.                                 x_parent = x_parent->parent;
  380.                         }
  381.                         else
  382.                         {
  383.                                 if (NULL == w->right || BLACK == w->right->color)
  384.                                 {
  385.                     if (NULL != w->left)
  386.                         w->left->color = BLACK;

  387.                                         w->color = RED;
  388.                                         Right_Rotate(w, root);
  389.                                         w = x_parent->right;
  390.                                 }

  391.                                 w->color = x_parent->color;
  392.                 x_parent->color = BLACK;
  393.                 if (NULL != w->right)
  394.                                     w->right->color  = BLACK;
  395.                                 Left_Rotate(x->parent, root);
  396.                 break;
  397.                         }
  398.                 }
  399.                 else
  400.         {
  401.                         w = x_parent->left;                                                                // w是x的兄弟结点

  402.                         if (RED == w->color)                                                                // 如果w的颜色是红色                                               
  403.                         {
  404.                                 w->color = BLACK;
  405.                                 x_parent->color = RED;
  406.                                 Right_Rotate(x_parent, root);
  407.                                 w = x_parent->left;
  408.                         }
  409.                         if ((NULL == w->left  || BLACK == w->left->color) &&
  410.                                 (NULL == w->right || BLACK == w->right->color))
  411.                         {
  412.                                 w->color = RED;
  413.                 x = x_parent;
  414.                                 x_parent = x_parent->parent;
  415.                         }
  416.                         else
  417.                         {
  418.                                 if (NULL == w->left || BLACK == w->left->color)
  419.                                 {
  420.                     if (NULL != w->right)
  421.                         w->right->color = BLACK;

  422.                                         w->color = RED;
  423.                                         Left_Rotate(w, root);
  424.                                         w = x_parent->left;
  425.                                 }

  426.                                 w->color = x_parent->color;
  427.                 x_parent->color = BLACK;
  428.                 if (NULL != w->left)
  429.                                     w->left->color  = BLACK;
  430.                                 Right_Rotate(x->parent, root);
  431.                 break;
  432.                         }
  433.                 }
  434.         }

  435.         x->color = BLACK;

  436.         return root;
  437. }

  438. void Print_Node(PRBTree node)
  439. {
  440.         char* color[] = {"BLACK", "RED"};
  441.         printf("Key = %d,\tcolor = %s", node->key, color[node->color]);
  442.         if (NULL != node->parent)
  443.                 printf(",\tparent = %d", node->parent->key);
  444.         if (NULL != node->left)
  445.                 printf(",\tleft = %d", node->left->key);
  446.         if (NULL != node->right)
  447.                 printf(",\tright = %d", node->right->key);
  448.         printf("\n");
  449. }

  450. // 中序遍历树, 加了一个判断, 如果输出的数据不满足序列关系就报错退出
  451. void Mid_Visit(PRBTree T)
  452. {
  453.         if (NULL != T)
  454.         {
  455.                 if (NULL != T->left)
  456.                 {
  457.                         if (T->left->key > T->key)
  458.                         {
  459.                                 printf("wrong!\n");
  460.                                 exit(-1);
  461.                         }
  462.                         Mid_Visit(T->left);
  463.                 }
  464.                 Print_Node(T);
  465.                 if (NULL != T->right)
  466.                 {
  467.                         if (T->right->key < T->key)
  468.                         {
  469.                                 printf("wrong\n");
  470.                                 exit(-1);
  471.                         }
  472.                         Mid_Visit(T->right);
  473.                 }
  474.         }
  475. }

  476. // 中序删除树的各个节点
  477. void Mid_DeleteTree(PRBTree T)
  478. {
  479.         if (NULL != T)
  480.         {
  481.                 if (NULL != T->left)
  482.                         Mid_DeleteTree(T->left);
  483.                 PRBTree temp = T->right;
  484.                 free(T);
  485.                 T = NULL;
  486.                 if (NULL != temp)
  487.                         Mid_DeleteTree(temp);
  488.         }
  489. }

  490. void Create_New_Array(int array[], int length)
  491. {
  492.         for (int i = 0; i < length; i++)
  493.         {
  494.                 array[i] = rand() % 256;
  495.         }
  496. }

  497. int main(int argc, char *argv[])
  498. {
  499.         srand(time(NULL));
  500.         PRBTree root = NULL;
  501.         int i;
  502.         for (i = 0; i < 100000; i++)
  503.         {
  504.                 root = RB_InsertNode(root, rand() % 10000);
  505.         }

  506.     Mid_Visit(root);

  507.         // 删除整颗树
  508.         Mid_DeleteTree(root);

  509.         return 0;
  510. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP