Introduce to algorithm--------pseudo code to C/C++ code(Chapter 8)

来源:互联网 发布:mac版pdf虚拟打印机 编辑:程序博客网 时间:2024/05/17 04:04

计数排序:

顾名思义,基数排序的中心思想是“计数”。该排序算法需要额外的两组array分别来存储计数信息和输出信息。

算法概述如下: 算法计算每个元素出现的次数,将次数按元素大小顺序保存。然后将每个出现次数更改为包

含自身次数以前的所有次数和。所以若元素5的累计次数为8,则元素5的最后一个排序位置(可能有多个元素5)应

该在数组中下标为7的位置处。(0-based index)必须要提的一点是计数排序的前提是非常重要的,即:假设n个输

入元素中的每一个都是在0到k区间内的一个整数,其中k为某个整数。(摘自算法导论)

[cpp] view plaincopyprint?
  1. //////////////////////////////////////////////////////////  
  2. //  A: input array   
  3. //  B: output array  
  4. //  n1:number of elements both in A and B arrays  
  5. //  C: auxiliary array  
  6. //  n2:number of elements in array C(the same as k + 1 said above)  
  7. /////////////////////////////////////////////////////////  
  8. template <typename T>  
  9. void counting_sort (T* A, T* B, int n1, T* C, int n2)  
  10. {  
  11.     //init auxiliary with 0  
  12.     for (int i = 0; i < n2; ++i)   
  13.         C[i] = static_cast<T> (0);  
  14.       
  15.     //counting number and save in array C with value located at A[i]  
  16.     for (int i = 0; i < n1; ++i)  
  17.         ++C[A[i]];  
  18.       
  19.     //accumulate counting numbers   
  20.     for (int i = 1; i < n2; ++i)  
  21.         C[i] += C[i - 1];  
  22.       
  23.     //input also sort  
  24.     for (int i = n1 - 1; i >= 0; --i)  
  25.         B[C[A[i]] - 1] = A[i],  
  26.         --C[A[i]];  
  27. }   
举例:排序A[] = { 2,3,5,1 }

输出数组:B;     辅助数组: C

第一个for循环:

B[] = { ?,?,?,? }

C[5] = { 0,0,0,0,0 }

第二个for循环:

B[] = { ?,?,?,? }

C[] = { 0,1,1,1,0,1 }因为存在一个元素2,所以C[2]递增。其他元素一样处理。

第三个for循环:

B[] = { ?,?,?,? }

C[] = { 0,1,2,3,3,4 }累计所有当前出现次数之前的所有出现次数的累加值(包括当前次数),用于定位元素的正确排序位置

第四个for循环:

B[] = { 1,2,3,5 }

基数排序:

顾名思义,基数排序基于“基数”这个概念。如果说数值为10进制数,则这些数值的基数为10,若数值为8进制数,则基数

为8.核心思想是根据数据的每位上的数值大小进行排序。以下图片描述的很清楚(摘自算法导论)


桶排序:
算法概念以“桶”为中心。以下为“桶”的概念:桶排序假设输入是由一个随机过程产生,该过程将元素均匀、独立的分布在[0,
1)

上,桶排序则将[0,1)划分为n个相同大小的子区间,称为桶。实际上,“桶”就是所有数据的一个块。桶排序分散在各个“桶”里进行。

但是输出各个桶排序后的数据时,只是简单的顺序遍历桶,所以在将数据分割成桶时,必须保证每个桶已按大小整体排序。



    由于实际上的应用,多数情况下是将基数排序与桶排序相结合以获得良好的运行时间,当然,是以相应的空间代价换来的。由于

桶排序是稳定排序,即排序时保持数据的原有相对顺序,所以将桶排序应用在技术排序中是完全可行的。以下为基数排序代码(内部

以桶排序实现):

[cpp] view plaincopyprint?
  1. ///////////////////////////////////////////////////////////////  
  2. //  function description:  
  3. //      radix sort uses buckets to make stable sort  
  4. //  parameter:  
  5. //      A:          array name  
  6. //      n:          array size  
  7. //      bitCount:   <span style="white-space:pre">    </span>max bit number of value  
  8. ///////////////////////////////////////////////////////////////  
  9. template <typename T>  
  10. void radix_sort (T* A, int n, int bitCount)  
  11. {  
  12.     //bucket sort in bit order  
  13.     for (int i = 1; i <= bitCount; ++i)  
  14.         bucket_sort<int> (A, n, bitCount);  
  15. }  
  16.   
  17. #define BaseNum     10  
  18.   
  19. template <typename T>  
  20. void bucket_sort (T* A, int num, int bitNum)  
  21. {  
  22.     //allocate bucket memory  
  23.     node<T>*      bucket[BaseNum];  
  24.       
  25.     //init  
  26.     for (int i = 0; i < BaseNum; ++i)  
  27.         bucket[i] = static_cast<node<T> *> (nullptr);  
  28.       
  29.     //sort using buckets  
  30.     int         temp = 1;  
  31.     for (int i = 0; i < bitNum - 1; ++i)  
  32.         temp *= BaseNum;      
  33.   
  34.     for (int i = 0; i < num; ++i)  
  35.         insertValue<T> (&bucket[A[i] / temp % BaseNum], A[i]);  
  36.       
  37.     //output in sequence order of buckets  
  38.     for (int i = 0, j = 0; i < BaseNum; ++i)  
  39.     {  
  40.         node<T>*  ptr = bucket[i];  
  41.         while (ptr)  
  42.             A[j++] = ptr->value,  
  43.             ptr = ptr->next;  
  44.     }  
  45. }  
  46.   
  47. template <typename T>  
  48. struct node   
  49. {  
  50.     T       value;  
  51.     node<T>       *next;  
  52. };  
  53.   
  54. //head is the bucket pointer  
  55. template <typename T>  
  56. void insertToNullList (node<T>** head, T value)  
  57. {  
  58.     *head = (node<T>*) malloc (sizeof (node<T>));  
  59.     (*head)->next = nullptr;  
  60.     (*head)->value = value;  
  61. }   
  62.   
  63. template <typename T>  
  64. void insertBetween (node<T>** left, node<T>* right, T value)  
  65. {  
  66.     (*left)->next = (node<T> *) malloc (sizeof  (node<T>));  
  67.     (*left)->next->next = right;  
  68.     (*left)->next->value = value;  
  69. }  
  70.   
  71. template <typename T>  
  72. void insertValue (node<T>** head, T value)  
  73. {  
  74.     //insert into empty list  
  75.     if (*head == nullptr)  
  76.         return insertToNullList<T> (head, value);  
  77.       
  78.     //if value in head node is greater, insert before it  
  79.     if ((*head)->value > value)  
  80.     {  
  81.         node<T>*  ptr = *head;  
  82.         *head = (node<T>*)malloc (sizeof (node<T>));  
  83.         (*head)->next = ptr;  
  84.         (*head)->value = value;  
  85.         return;  
  86.     }  
  87.       
  88.     //locate the appropriate place  
  89.     node<T>   *ptr = *head;  
  90.     while (ptr->next && ptr->next->value <= value)  
  91.         ptr = ptr->next;  
  92.   
  93.     //insert into tail  
  94.     if (ptr->next == nullptr)  
  95.         insertToNullList<T> (&ptr->next, value);  
  96.     else  
  97.         //insert inside list  
  98.         insertBetween<T> (&ptr, ptr->next, value);  
  99. }  

虽然出于代码复用的考虑用模板来实现了,但仅限于int,long等类似类型,不适用于unsigned,float等类型。还有,作为一个算法函数

而言,个人觉得应这样实现该是不推荐的。当时实现的时候自己太过关注代码的重用,并且有一部分是出于熟练模板的使用与设计。虚心请

球批评指正。

For more details,  see Introduce to algorithm.

0 0