注:本文改编自windmissing博客,感谢作者整理!

 

题目:

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

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

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

 

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