算法导论-8-3-排序不同长度的数据项

来源:互联网 发布:灰度梯度共生矩阵 编辑:程序博客网 时间:2024/06/05 12:46

一、题目

a)给定一个整数数组,其中不同的整数中包含的数字个数可能不同,但是该数组中,所有整数中总的数字数为n。说明如何在O(n)时间内对该数组进行排序

b)给定一个字符串数组,其中不同的串包含的字符个数可能不同,但所有串中总的字符个数为n。说明如何在O(n)时间内对该数组进行排序

(注意此处的顺序是指标准的字母顺序,例如,a < ab < b)

 

二、思路

a)先用计数排序算法按数字位数排序O(n),再用基数排序的方法分别对每个桶中的元素排序O(n)
b)递归使用计数排序,先依据第一个字母进行排序,首字相同的放在同一组,再对每一组分别使用计数排序的方法比较第二个字母
见到有人用字典树,也是可以的,见算法导论-12-2-基数树

三、代码

a)

[cpp] view plaincopyprint?
  1. //8-2-a   
  2. #include <iostream>   
  3. #include <cmath>   
  4. using namespace std;  
  5.   
  6. int length_A;  
  7. void Print(int *A)  
  8. {  
  9.     int i;  
  10.     for(i = 1; i <= length_A; i++)  
  11.         cout<<A[i]<<' ';  
  12.     cout<<endl;  
  13. }  
  14. int Digit(int x)  
  15. {  
  16.     int ret = 0;  
  17.     while(x)  
  18.     {  
  19.         ret++;  
  20.         x = x / 10;  
  21.     }  
  22.     return ret;  
  23. }  
  24. //基数排序调用的稳定排序   
  25. void Counting_Sort(int *A, int *B, int k)  
  26. {  
  27.     int i, j;  
  28.     //将C数组初始化为0,用于计数   
  29.     int *C = new int[k+1];  
  30.     for(i = 0; i <= k; i++)  
  31.         C[i] = 0;  
  32.     int *D = new int[length_A+1];  
  33.     for(j = 1; j <= length_A; j++)  
  34.     {  
  35.         //D[j]表示第[j]个元素有i位数字   
  36.         D[j] = Digit(A[j]);  
  37.         //C[j]表示数字D[j]在数组A中出现的次数  
  38.         C[D[j]]++;  
  39.     }  
  40.     //C[i]表示所以<=i的数字出现过的次数   
  41.     for(i = 1; i <= k; i++)  
  42.         C[i] = C[i] + C[i-1];  
  43.     //初始化B为0,B用于输出排序结果   
  44.     for(i = 1; i <= length_A; i++)  
  45.         B[i] = 0;  
  46.     for(j = length_A; j >= 1; j--)  
  47.     {  
  48.         //如果<=D[j]的数字的个数是x,那么排序后A[j]应该出现在第x个位置,即B[x]=A[j]  
  49.         B[C[D[j]]] = A[j];  
  50.         C[D[j]]--;  
  51.     }  
  52.     delete []C;  
  53.     delete []D;  
  54. }  
  55. //基数排序调用的稳定排序   
  56. void Stable_Sort(int *A, int *B, int k, int d,int start, int end)  
  57. {  
  58.     int i, j, radix = 10;  
  59.     //将C数组初始化为0,用于计数   
  60.     int *C = new int[k+1];  
  61.     for(i = 0; i <= k; i++)  
  62.         C[i] = 0;  
  63.     int *D = new int[length_A+1];  
  64.     for(j = start; j <= end; j++)  
  65.     {  
  66.         //D[j]表示第[j]个元素的第i位数字   
  67.         D[j] = A[j] % (int)pow(radix*1.0, d) / (int)pow(radix*1.0, d-1);  
  68.         //C[j]表示数字D[j]在数组A中出现的次数   
  69.         C[D[j]]++;  
  70.     }  
  71.     //C[i]表示所以<=i的数字出现过的次数   
  72.     for(i = 1; i <= k; i++)  
  73.         C[i] = C[i] + C[i-1];  
  74.     //初始化B为0,B用于输出排序结果   
  75.     for(i = 1; i <= length_A; i++)  
  76.         B[i] = 0;  
  77.     for(j = end; j >= start; j--)  
  78.     {  
  79.         //如果<=D[j]的数字的个数是x,那么排序后A[j]应该出现在第x个位置,即B[x]=A[j]  
  80.         B[C[D[j]]+start-1] = A[j];  
  81.         C[D[j]]--;  
  82.     }  
  83.     delete []C;  
  84.     delete []D;  
  85. }  
  86. void Radix_Sort(int *A, int *B, int k ,int digit, int start, int end)  
  87. {  
  88.     int i, j;  
  89.     //依次对每一位进行排序,从低位到高位   
  90.     for(i = 1; i <= digit; i++)  
  91.     {  
  92.         Stable_Sort(A, B, k, i, start, end);  
  93.         //输入的是A,输出的是B,再次排序时要把输出数据放入输出数据中  
  94.         for(j = start; j <= end; j++)  
  95.         A[j] = B[j];  
  96.     }  
  97. }  
  98. int main()  
  99. {  
  100.     cin>>length_A;  
  101.     int i;  
  102.     //产生随机的测试数据   
  103.     int *A = new int[length_A+1];  
  104.     for(i = 1; i <= length_A; i++)  
  105.         A[i] = rand() % (int)pow(10.0, rand()%5+1);  
  106.     Print(A);  
  107.     int *B = new int[length_A+1];  
  108.     //先进行计数排序,把长度相同的数字排在一起   
  109.     Counting_Sort(A, B, 5);  
  110.     for(i = 1; i <= length_A; i++)  
  111.         A[i] = B[i];  
  112.     Print(A);  
  113.     int start, end, digit = -1;  
  114.     for(i = 1; i <= length_A; i++)  
  115.     {  
  116.         if(digit == -1)  
  117.         {  
  118.             digit = Digit(A[i]);  
  119.             start = i;  
  120.             end = i;  
  121.         }  
  122.         else  
  123.         {  
  124.             if(Digit(A[i]) == digit)  
  125.                 end = i;  
  126.             else  
  127.             {  
  128.                 //找到位数相同的一段,从start到end,单独对这一段进行基数排序  
  129.                 Radix_Sort(A, B, 9, digit, start, end);  
  130.                 i--;  
  131.                 digit = -1;  
  132.                 Print(A);  
  133.             }  
  134.         }  
  135.     }  
  136.     delete []A;  
  137.     delete []B;  
  138. }  

 


b)

[cpp] view plaincopyprint?
  1. #include <iostream>   
  2. #include <string>   
  3. using namespace std;  
  4.   
  5. int length_A;  
  6. void Print(string *A)  
  7. {  
  8.     int i;  
  9.     for(i = 1; i <= length_A; i++)  
  10.         cout<<A[i]<<' ';  
  11.     cout<<endl;  
  12. }  
  13. //基数排序调用的稳定排序,A是输入,B是中间输出,C是计数,d表示对第d位字母排序,start和end分别是排序段的起点和终点  
  14. void Counting_Sort(string *A, string *B, int *C, int d, int start, int end)  
  15. {  
  16.     if(start == end)  
  17.         return;  
  18.     int i, j;  
  19.     //将C数组初始化为0,用于计数   
  20.     for(i = 0; i <= 26; i++)  
  21.         C[i] = 0;  
  22.     int *D = new int[length_A+1];  
  23.     for(j = start; j <= end; j++)  
  24.     {  
  25.         //D[j]表示第[j]个元素的第i位数字   
  26.         if(A[j].length() <= d)  
  27.             D[j] = 0;  
  28.         else  
  29.             D[j] = A[j][d] - 'a';  
  30.         //C[j]表示数字D[j]在数组A中出现的次数   
  31.         C[D[j]]++;  
  32.     }  
  33.     //C[i]表示所以<=i的数字出现过的次数   
  34.     for(i = 1; i <= 26; i++)  
  35.         C[i] = C[i] + C[i-1];  
  36.     //初始化B为0,B用于输出排序结果   
  37.     for(i = 1; i <= length_A; i++)  
  38.         B[i] = "";  
  39.     for(j = end; j >= start; j--)  
  40.     {  
  41.         //如果<=D[j]的数字的个数是x,那么排序后A[j]应该出现在第x个位置,即B[x]=A[j]  
  42.         B[C[D[j]]+start-1] = A[j];  
  43.         C[D[j]]--;  
  44.     }  
  45.     delete []D;  
  46.     //输出转为输入   
  47.     for(i = start; i <= end; i++)  
  48.         A[i] = B[i];  
  49.     char c = 'A';  
  50.     int s, e;//进一步的排序以s为起点,e为终点  
  51.     //对于排序的这一段,对下一个字母递归使用计数排序   
  52.     for(i = start; i <= end; i++)  
  53.     {  
  54.         //如果长度为d,不参与下一步排序   
  55.         if(A[i][d] == '\0')  
  56.             continue;  
  57.         if(c == 'A')  
  58.         {  
  59.             s = i;  
  60.             e = i;  
  61.             c = A[i][d];  
  62.         }  
  63.         else  
  64.         {  
  65.             if(A[i][d] == c)  
  66.             {  
  67.                 e = i;  
  68.                 if(e == end)  
  69.                     //以第d+1位字母为依据,对s-e段进行计数排序  
  70.                     Counting_Sort(A, B, C, d+1, s, e);  
  71.             }  
  72.             else  
  73.             {  
  74.                 //以第d+1位字母为依据,对s-e段进行计数排序   
  75.                 Counting_Sort(A, B, C, d+1, s, e);  
  76.                 i--;  
  77.                 c = 'A';  
  78.             }  
  79.         }  
  80.     }  
  81. }  
  82. int main()  
  83. {  
  84.     int i, j;  
  85.     cin>>length_A;  
  86.     string *A = new string[length_A+1];  
  87.     //构造随机数据   
  88.     for(i = 1; i <= length_A; i++)  
  89.     {  
  90.         int len = rand()%5+1;  
  91.         for(j = 1; j <= len; j++)  
  92.             A[i] = A[i] + (char)(rand()%26+'a');  
  93.     }  
  94.     Print(A);  
  95.     string *B = new string[length_A+1];  
  96.     int *C = new int[26];  
  97.     //计数排序   
  98.     Counting_Sort(A, B, C, 0, 1, length_A);  
  99.     Print(A);  
  100.     delete []A;  
  101.     delete []C;  
  102.     return 0;  
  103. }  


 

四、效果:

a)

 

b)

 

转载自:http://blog.csdn.net/mishifangxiangdefeng/article/details/7686099
原创粉丝点击