免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 12054 | 回复: 24
打印 上一主题 下一主题

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

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-03-04 22:42 |只看该作者 |倒序浏览
第二章中给出的Merge算法,本质是初始化两个数组分别保存前后两个已经排序好了的数组,然后逐个扫描比较两个数组中的元素把元素放在原来数组的合适的位置上.
     不知道之前有没有人做过这个算法,比起书上的那个并不见得高明,在最坏的情况下要交换元素(N/2)*(N/2)也就是N的平方数量级(这里N是数组的大小),这个最坏的情况就是前面的数组中的元素都比后面数组的元素大.
       虽然不见得是最好的,不过至少是自己思考的结果,放上来也许对别人有启发.


  1. // 如何证明算法的正确性?
  2. // 我写的merge算法
  3. void Merge1(int array[], int start, int mid, int end)
  4. {
  5.     // 思想:设置两个哨兵,分别指向前后两个数组,
  6.     // 逐个把前面的数组的元素和后面数组的元素进行比较
  7.     // 如果前面的元素不比后面的元素大,那么前面数组的哨兵前移一位
  8.     // 否则,交换两个元素,并且对后面的数组进行扫描,确保新的元素放在合适的位置
  9.     // 当前面的数组扫描完毕之后循环结束
  10.     for (int i = start; i < mid + 1; ++i)
  11.     {
  12.         if (array[i] > array[mid + 1])
  13.         {
  14.             swap(&array[i], &array[mid + 1]);

  15.             // 把新放入后面数组的元素放到合适的位置去
  16.             for (int j = mid +1; j + 1 <= end && array[j] > array[j + 1]; ++j)
  17.             {
  18.                 swap(&array[j], &array[j + 1]);
  19.             }
  20.         }      
  21.     }
  22. }

  23. // 书上的算法实现
  24. void Merge(int array[], int start, int mid, int end)
  25. {
  26.     int temp1[10], temp2[10];
  27.     int n1, n2;
  28.     n1 = mid - start + 1;
  29.     n2 = end - mid;

  30.     // 拷贝前半部分数组
  31.     for (int i = 0; i < n1; i++)
  32.     {
  33.         temp1[i] = array[start + i];
  34.     }
  35.     // 拷贝后半部分数组
  36.     for (int i = 0; i < n2; i++)
  37.     {
  38.         temp2[i] = array[mid + i + 1];
  39.     }
  40.     // 把后面的元素设置的很大
  41.     temp1[n1] = temp2[n2] = 1000;
  42.     // 逐个扫描两部分数组然后放到相应的位置去
  43.     for (int k = start, i = 0, j = 0; k <= end; k++)
  44.     {
  45.         if (temp1[i] <= temp2[j])
  46.         {
  47.             array[k] = temp1[i];
  48.             i++;
  49.         }
  50.         else
  51.         {
  52.             array[k] = temp2[j];
  53.             j++;
  54.         }
  55.     }
  56. }

  57. void Merge_Sort(int array[], int start, int end)
  58. {
  59.     if (start < end)
  60.     {
  61.         int i;
  62.         i = (end + start) / 2;
  63.         Merge_Sort(array, start, i);
  64.         Merge_Sort(array, i + 1, end);

  65.         Merge1(array, start, i, end);
  66.         //Merge(array, start, i, end);
  67.     }
  68. }
复制代码


对外的接口:Merge_Sort(array, start, end);
即:传入一个数组,和起始位置中止位置,比如数组array[10],那么就是Merge_Sort(arrry,0,9)
附带的说明:在Merge中,也就是书中的算法实现部分,初始化的两个temp数组都是10大小的,另外,最后存储完了两部分的数组元素之后放了一个"足够大"的数值1000,相应的都可以改变,这里为求简单方便所以进行了一些限制.

[ 本帖最后由 converse 于 2006-3-21 23:20 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2006-03-04 22:58 |只看该作者
我不懂  也没细看:wink:

但只要扫一眼就可以看出:

你的算法的复杂度:O(n*n)

书上算法的复杂度:O(n)


显然书上的算法好

论坛徽章:
0
3 [报告]
发表于 2006-03-04 23:06 |只看该作者
原帖由 ammy 于 2006-3-4 22:58 发表
我不懂  也没细看:wink:

但只要扫一眼就可以看出:

你的算法的复杂度:O(n*n)

书上算法的复杂度:O(n)


显然书上的算法好


我知道我的不好,不过多一个想法记录一下罢了...

论坛徽章:
0
4 [报告]
发表于 2006-03-04 23:38 |只看该作者
原帖由 converse 于 2006-3-4 23:06 发表


我知道我的不好,不过多一个想法记录一下罢了...


呵呵  偶是菜鸟  

今儿个不小心  从清茶灌到这儿来了  打扰:wink:

两周看<<算法导论>>的一章,估计一年下来我可以看完了~~


我估计你看不完了

论坛徽章:
0
5 [报告]
发表于 2006-03-04 23:45 |只看该作者
原帖由 ammy 于 2006-3-4 23:38 发表


呵呵  偶是菜鸟  

今儿个不小心  从清茶灌到这儿来了  打扰:wink:



我估计你看不完了


这个是我跟自己在较劲...结果未知...
OK,别在技术帖子里面谈论也技术不太相关的事情了,不然斑竹删了我的帖子了...

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
6 [报告]
发表于 2006-03-05 09:52 |只看该作者
你首先得介绍一下你的程序的功能啊。
晕死,不然还得去找第二章……

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

红黑树的代码


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

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

  11. 红黑树的几个性质:
  12. 1) 每个结点只有红和黑两种颜色
  13. 2) 根结点是黑色的
  14. 3) 每个叶子结点(空结点被认为是叶子结点)是黑色的
  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 z);

  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.         if (NULL == B)
  57.                 return;

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

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

  89.         if (NULL == B)
  90.                 return;

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

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

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

  140.         return x;
  141. }

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

  150.         PRBTree z;
  151.         if (NULL == (z = (PRBTree)malloc(sizeof(RBTree))))
  152.         {
  153.                 printf("Memory alloc error\n");
  154.                 return NULL;
  155.         }
  156.         z->key = key;

  157.         // 得到z的父节点
  158.         x = root, y = NULL;
  159.         while (NULL != x)
  160.         {
  161.                 y = x;
  162.                 if (z->key < x->key)
  163.                 {
  164.                         if (NULL != x->left)
  165.                         {
  166.                                 x = x->left;
  167.                         }
  168.                         else
  169.                         {
  170.                                 break;
  171.                         }
  172.                 }
  173.                 else
  174.                 {
  175.                         if (NULL != x->right)
  176.                         {
  177.                                 x = x->right;
  178.                         }
  179.                         else
  180.                         {
  181.                                 break;
  182.                         }
  183.                 }
  184.         }

  185.         // 把z放到合适的位置
  186.         z->parent = y;
  187.         if (NULL == y)
  188.         {
  189.                 root = z;
  190.         }
  191.         else
  192.         {
  193.                 if (z->key < y->key)
  194.                         y->left = z;
  195.                 else
  196.                         y->right = z;
  197.         }
  198.         // 设置z的左右子树为空并且颜色是red,注意新插入的节点颜色都是red
  199.         z->left = z->right = NULL;
  200.         z->color = RED;

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

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

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

  261.         return root;
  262. }

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

  271.         z = Find_Node(root, key);
  272.         if (NULL == z)
  273.                 return root;

  274.         // 当z有一个空子树的时候,y == z
  275.         // 否则,y是大于z最小的结点
  276.         if (NULL == z->left || NULL == z->right)
  277.                 y = z;
  278.         else
  279.         {
  280.                 y = z->right;
  281.                 while (NULL != y->left)
  282.                         y = y->left;
  283.         }

  284.         // x是y的子树,可能为NULL
  285.         if (NULL != y->left)
  286.                 x = y->left;
  287.         else
  288.                 x = y->right;

  289.         // 设定x的位置取代y
  290.         if (NULL != x)
  291.                 x->parent = y->parent;
  292.         if (NULL == y->parent)
  293.                 root = x;
  294.         else if (y == y->parent->left)
  295.                 y->parent->left = x;
  296.         else
  297.                 y->parent->right = x;

  298.         // 把y的key拷贝到z中,这样y就是待删除的结点了
  299.         if (y != z)
  300.         {
  301.                 z->key = y->key;
  302.         }

  303.         // 如果y的颜色值是B,那么要对树进行修正
  304.         if (BLACK == y->color && NULL != x)
  305.                 RB_DeleteNode_Fixup(root, x);

  306.         free(y);

  307.         return root;
  308. }

  309. /*-----------------------------------------------------------
  310. |        函数作用:对删除key值之后的树进行修正
  311. |        输入参数:根节点root,删除的结点的子结点x
  312. |        返回参数:根节点root
  313. -------------------------------------------------------------*/
  314. PRBTree RB_DeleteNode_Fixup(PRBTree root, PRBTree x)
  315. {
  316.         PRBTree w;

  317.         while (x != root && BLACK == x->color)
  318.         {
  319.                 if (x == x->parent->left)                                                                // 如果x是左子树
  320.                 {
  321.                         w = x->parent->right;                                                                // w是x的兄弟结点

  322.                         if (NULL == w)
  323.                                 continue;

  324.                         if (RED == w->color)                                                                // 如果w的颜色是红色                                               
  325.                         {
  326.                                 w->color = BLACK;
  327.                                 x->parent->color = RED;
  328.                                 Left_Rotate(x->parent, root);
  329.                                 w = x->parent->right;
  330.                         }
  331.                         if (NULL != w->left         && BLACK == w->left->color &&
  332.                                 NULL != w->right && BLACK == w->right->color)
  333.                         {
  334.                                 w->color = RED;
  335.                                 x = x->parent;
  336.                         }
  337.                         else
  338.                         {
  339.                                 if (NULL != w->right && BLACK == w->right->color)
  340.                                 {
  341.                                         w->left->color = BLACK;
  342.                                         w->color = RED;
  343.                                         Right_Rotate(w, root);
  344.                                         w = x->parent->right;
  345.                                 }

  346.                                 w->color = x->parent->color;
  347.                                 x->parent->color = BLACK;
  348.                                 w->right->color  = BLACK;
  349.                                 Left_Rotate(x->parent, root);
  350.                                 x = root;
  351.                         }
  352.                 }
  353.                 else
  354.                 {
  355.                         w = x->parent->left;
  356.                         if (NULL == w)
  357.                                 continue;
  358.                         if (RED == w->color)
  359.                         {
  360.                                 w->color = BLACK;
  361.                                 x->parent->color = RED;
  362.                                 Left_Rotate(x->parent, root);
  363.                                 w = x->parent->left;
  364.                         }
  365.                         if (NULL != w->left         && BLACK == w->left->color &&
  366.                                 NULL != w->right && BLACK == w->right->color)
  367.                         {
  368.                                 w->color = RED;
  369.                                 x = x->parent;
  370.                         }
  371.                         else
  372.                         {
  373.                                 if (NULL != w->left && BLACK == w->left->color)
  374.                                 {
  375.                                         w->right->color = BLACK;
  376.                                         w->color = RED;
  377.                                         Left_Rotate(w, root);
  378.                                         w = x->parent->left;
  379.                                 }

  380.                                 w->color = x->parent->color;
  381.                                 x->parent->color = BLACK;
  382.                                 w->left->color  = BLACK;
  383.                                 Right_Rotate(x->parent, root);
  384.                                 x = root;
  385.                         }
  386.                 }
  387.         }

  388.         x->color = BLACK;

  389.         return root;
  390. }

  391. void Print_Node(PRBTree node)
  392. {
  393.         char* color[] = {"BLACK", "RED"};
  394.         printf("Key = %d,\tcolor = %s", node->key, color[node->color]);
  395.         if (NULL != node->parent)
  396.                 printf(",\tparent = %d", node->parent->key);
  397.         if (NULL != node->left)
  398.                 printf(",\tleft = %d", node->left->key);
  399.         if (NULL != node->right)
  400.                 printf(",\tright = %d", node->right->key);
  401.         printf("\n");
  402. }

  403. // 中序遍历树
  404. void Mid_Visit(PRBTree T)
  405. {
  406.         if (NULL != T)
  407.         {
  408.                 if (NULL != T->left)
  409.                         Mid_Visit(T->left);
  410.                 Print_Node(T);
  411.                 if (NULL != T->right)
  412.                         Mid_Visit(T->right);
  413.         }
  414. }

  415. // 中序删除树的各个节点
  416. void Mid_DeleteTree(PRBTree T)
  417. {
  418.         if (NULL != T)
  419.         {
  420.                 if (NULL != T->left)
  421.                         Mid_DeleteTree(T->left);
  422.                 PRBTree temp = T->right;
  423.                 free(T);
  424.                 T = NULL;
  425.                 if (NULL != temp)
  426.                         Mid_DeleteTree(temp);
  427.         }
  428. }

  429. void Create_New_Array(int array[], int length)
  430. {
  431.         for (int i = 0; i < length; i++)
  432.         {
  433.                 array[i] = rand() % 256;
  434.         }
  435. }

  436. int main(int argc, char *argv[])
  437. {
  438.         //int array[10] = {80, 116, 81, 205, 82, 68, 151, 20, 109, 100};
  439.         int array[10];
  440.         srand(time(NULL));
  441.         Create_New_Array(array, 10);
  442.         PRBTree root = NULL;
  443.         int i;
  444.         for (i = 0; i < 10; i++)
  445.         {
  446.                 root = RB_InsertNode(root, array[i]);
  447.         }

  448.         Mid_Visit(root);

  449.         // 随机删除一个结点
  450.         int index = rand() % 10;
  451.         printf("delete node %d\n", array[index]);
  452.         root = RB_DeleteNode(root, array[index]);
  453.         Mid_Visit(root);

  454.         // 删除整颗树
  455.         Mid_DeleteTree(root);

  456.         return 0;
  457. }


复制代码


先把代码放上来,基本按照书上的算法写作的,相应的文档整理中,看<<算法导论>>有点头大了,看来两周一篇的任务很是艰难了。

[ 本帖最后由 converse 于 2006-3-21 23:28 编辑 ]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
8 [报告]
发表于 2006-03-21 23:25 |只看该作者
看的是英文版还是中文版?

论坛徽章:
0
9 [报告]
发表于 2006-03-21 23:28 |只看该作者
原帖由 lenovo 于 2006-3-21 23:25 发表
看的是英文版还是中文版?


英文,中文那本是第一版了,英文的是第二版的

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

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

书上:

14.1-2

Suppose that the root of a red-black tree is red. If we make it black, does the tree remain a red-black tree?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP