計數,基數的中文讀音都同樣,這翻譯的人還嫌咱們計算機不夠亂,真的想吐槽。算法
無論了,畢竟代碼仍是不同的。函數
一、計數排序(counter sort):測試
經過一個上限來統計集合裏的數值(或者其餘非數值類型映射的數值),並累計比小於本身(包括)的數值的統計的個數,從而造成排序的索引(也就是前面有多少個小於個人,個人位置就肯定了)。優化
普通計數排序代碼:(仍需優化,valuetype默認是整數類型)spa
1 template<typename _InIt> 2 void counter_sort(_InIt first, _InIt last, int k, _InIt result) { 3 typedef typename iterator_traits<_InIt>::value_type _ValueType; 4 5 vector<_ValueType> v(k, _ValueType(0)); 6 for(_InIt it=first; it!=last; ++it) v[*it]++; 7 8 typename vector<_ValueType>::iterator itx = v.begin()+1; 9 for(; itx!=v.end() ; ++itx) (*itx) += *(itx-1); 10 11 for (int i = last - first -1; i>=0; i--) { 12 _ValueType val = *(first+i); 13 *(result + v[val] - 1) = val; 14 v[val]--; 15 } 16 }
二、基數排序(radix sort)翻譯
基數排序道理挺容易理解,算法導論裏有圖解。不過看到有關ACM的一篇文章裏提到MSD(Most Significant Dight)和LSD(Least Significant Dight)排序,也就是說從那邊開始排序效率高,舉個整數的例子,3位數,假如每一個數最高位都不重複,那確定是從數值的最高位排一次就排好序了。不過實際中太多數可能不是這種狀況,因此這個只能說跟那個大端小端同樣,從那邊開始根據具體狀況來看。設計
下面是代碼,修改一下計數排序來適配數值的位數變化。code
1 template<typename T> 2 void print(const vector<T>& v) { 3 for(vector<int>::const_iterator it=v.begin(); it != v.end(); it++) 4 cout << *it << " "; 5 cout << endl; 6 } 7 8 int decimal_num(int num, int p) { 9 assert(num >0 && p > 0); 10 int s = 1; 11 while (p-->0) s *= 10; 12 return ((num%s)*10)/s; 13 } 14 15 template<typename _InIt> 16 void counter_sort(_InIt first, _InIt last, _InIt result, int k, int p) { 17 typedef typename iterator_traits<_InIt>::value_type _ValueType; 18 19 vector<_ValueType> v(k, _ValueType(0)); 20 for(_InIt it=first; it!=last; ++it) v[decimal_num(*it, p)]++; 21 22 typename vector<_ValueType>::iterator itx = v.begin()+1; 23 for(; itx!=v.end() ; ++itx) (*itx) += *(itx-1); 24 25 for (int i = last - first -1; i>=0; i--) { 26 _ValueType val = *(first+i); 27 _ValueType idx = decimal_num(val, p); 28 29 *(result + v[idx] - 1) = val; 30 v[idx]--; 31 } 32 33 for(_InIt it = first; it!=last; ++it) *it = *result++; 34 } 35 36 template<typename _InIt> 37 void radix_sort(_InIt first, _InIt last, _InIt result, int p) { /* 參數p是要排序的整數的最大位數,好比998就是3位數 p=3 */ 38 for (int i=1; i<=p; i++) { 39 counter_sort(first, last, result, 10, i); 40 } 41 } 42 43 int main() { 44 int lst[] = {2,5,0,3,2,3,0,3}; 45 vector<int> v(lst, lst+8); 46 vector<int> v2(v.size(), 0); 47 48 counter_sort(v.begin(), v.end(), 6, v2.begin()); 49 print(v2); 50 51 //int lst2[] = {329,457,657,839,436,720,355}; 52 int lst2[10] = {20, 80, 90, 589, 998, 965, 852, 123, 456, 789}; 53 vector<int> v3(lst2, lst2+10); 54 vector<int> v4(v3.size(), 0); 55 56 radix_sort(v3.begin(), v3.end(), v4.begin(), 3); 57 print(v4); 58 59 return 0; 60 }
遇到的問題:blog
一、取十進制每一個位的值,一開始我是採用pow函數,後來測試發現pow(10.0,2)竟然等於99.0,因此本身實現了10的平方運算。排序
二、每次基數排序時要使用上一次的排序結果,就是計數排序以後多了一個從新賦值的操做,這個開銷是否能夠去掉,想交替使用2個vector應該能夠解決問題,可是須要肯定最後的結果在哪一個vector裏,又對現有函數接口改動太大。
三、數值運算過多,還須要考慮乘法運算溢出。
補充一個運行結果:
1 0 0 2 2 3 3 3 5 2 20 80 90 123 456 589 789 852 965 998 3 4 Process returned 0 (0x0) execution time : 0.100 s 5 Press any key to continue.
偷懶圖便利就手工測試啦,後面的問題愈來愈難,仍是得弄一下gtest。
爲了解決上面賦值問題,從新設計了函數接口,若是位數爲奇數就是第二個vector,若是是偶數就是第一個帶初始數據的vector爲最後的排序結果:
1 template<typename _InIt> 2 void counter_sort(_InIt first, _InIt last, _InIt result, int k, int p) { 3 typedef typename iterator_traits<_InIt>::value_type _ValueType; 4 5 vector<_ValueType> v(k, _ValueType(0)); 6 for(_InIt it=first; it!=last; ++it) v[decimal_num(*it, p)]++; 7 8 typename vector<_ValueType>::iterator itx = v.begin()+1; 9 for(; itx!=v.end() ; ++itx) (*itx) += *(itx-1); 10 11 for (int i = last - first -1; i>=0; i--) { 12 _ValueType val = *(first+i); 13 _ValueType idx = decimal_num(val, p); 14 _ValueType vv = v[idx]; 15 *(result + v[idx] - 1) = val; 16 v[idx]--; 17 } 18 } 19 20 template<typename _InIt> 21 void swap_iter(_InIt& it1, _InIt& it2) { 22 _InIt it = it1; 23 it1 = it2; 24 it2 = it; 25 } 26 27 template<typename _InIt> 28 void swap_iter(_InIt& f1, _InIt& l1, _InIt& f2, _InIt& l2) { 29 swap_iter(f1, f2); 30 swap_iter(l1, l2); 31 } 32 33 template<typename _InIt> 34 void radix_sort(_InIt first, _InIt last, _InIt result, _InIt result_end, int p) { 35 for (int i=1; i<=p; i++) { 36 counter_sort(first, last, result, 10, i); 37 swap_iter(first, last, result, result_end); 38 } 39 }
問題解決了,可是以爲不是很優雅,後面再迭代吧。