算法導論第三版--計數,基數排序

計數,基數的中文讀音都同樣,這翻譯的人還嫌咱們計算機不夠亂,真的想吐槽。算法

無論了,畢竟代碼仍是不同的。函數

 

一、計數排序(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 }

問題解決了,可是以爲不是很優雅,後面再迭代吧。

相關文章
相關標籤/搜索