注:本文改编自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 }