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