count sort, radix sort, bucket sort
count sort, radix sort, bucket sort
標(biāo)簽(空格分隔): algorithms
基于比較的排序算法,都逃不過(guò)O(nlogn)O(nlogn)O(nlogn)的宿命1。而非基于比較的排序,如計(jì)數(shù)排序,基數(shù)排序,桶排序則無(wú)此限制。它們充分利用待排序的數(shù)據(jù)的某些限定性假設(shè),來(lái)避免絕大多數(shù)的“比較”操作。
計(jì)數(shù)排序
http://www.geeksforgeeks.org/counting-sort/
時(shí)間復(fù)雜度:O(N+K)O(N+K)O(N+K),N為元素個(gè)數(shù),K為元素最大值。是一種穩(wěn)定的排序算法。
但是我覺(jué)得時(shí)間復(fù)雜度其實(shí)還是O(N)O(N)O(N),因?yàn)椴还苁怯?jì)數(shù)還是最后把每個(gè)元素放入正確的位置都是O(N)O(N)O(N)。
#include <string> #include <vector> #include <iostream>using namespace std;/* O(n+k) 最后count數(shù)組相當(dāng)于往后移了一個(gè)元素。 */void count_sort(string &s) {const int range = 255;vector<int> count(range+1,0);for (auto c : s)count[c]++;for (int i = 1; i <= range; i++)count[i] += count[i-1];string temp(s.size(), ' ');//如果改成從右到左循環(huán),則是穩(wěn)定的。//當(dāng)然還有一種做法,即不用累加count數(shù)組,直接掃描count數(shù)組,設(shè)置一個(gè)全局index,這樣會(huì)有問(wèn)題:不穩(wěn)定。但改成從右到左循環(huán),還是穩(wěn)定的。/*for (int i = s.size()-1; i >= 0; i--){temp[count[s[i]] = s[i];count[s[i]]--;}*/for (auto c : s){temp[count[c]-1] = c;count[c]--;}s = temp;}int main() {string s = "geeksforgeeks";count_sort(s);cout << s << endl; }基數(shù)排序
http://www.geeksforgeeks.org/radix-sort/
http://notepad.yehyeh.net/Content/Algorithm/Sort/Radix/Radix.php
基數(shù)排序的底層排序可以用計(jì)數(shù)排序或者桶排序。
Let there be ddd digits in input integers. Radix Sort takes O(d?(n+b))O(d*(n+b))O(d?(n+b)) time where bbb is the base for representing numbers, for example, for decimal system, bbb is 10. What is the value of ddd? If kkk is the maximum possible value, then ddd would be O(logb(k))O(log_b(k))O(logb?(k)). (比如k=1000,b=10,則d=3)So overall time complexity is O((n+b)?logb(k))O((n+b) * log_b(k))O((n+b)?logb?(k)). Which looks more than the time complexity of comparison based sorting algorithms for a large kkk. Let us first limit kkk. Let k<=nck <= n^ck<=nc where ccc is a constant. In that case, the complexity becomes O(nlogb(n))O(nlog_b(n))O(nlogb?(n)). But it still doesn’t beat comparison based sorting algorithms.
What if we make value of bbb larger?. What should be the value of bbb
to make the time complexity linear? If we set bbb as nnn, we get the
time complexity as O(n)O(n)O(n). In other words, we can sort an array of
integers with range from 1 to ncn^cnc if the numbers are represented in
base nnn (or every digit takes log2(n)log_2(n)log2?(n) bits).
上面最后一段說(shuō),如果要給111~ncn^cnc之內(nèi)的以nnn為基數(shù)的數(shù)組排序,那么就可以用線性的復(fù)雜度完成。
問(wèn)題:對(duì)[0,n2?1][0,n^2-1][0,n2?1]的nnn 個(gè)整數(shù)進(jìn)行線性時(shí)間排序。
方法1是先把整數(shù)轉(zhuǎn)換成n進(jìn)制再排序,這樣每個(gè)數(shù)有兩位,范圍為[0…n-1],再進(jìn)行基數(shù)排序。http://blog.csdn.net/mishifangxiangdefeng/article/details/7685839
LSD:從關(guān)鍵字優(yōu)先級(jí)低的開始排,循環(huán)
MSD:從關(guān)鍵字優(yōu)先級(jí)高的開始排,遞歸
lsd適合于定長(zhǎng)的字符串?dāng)?shù)組排序:
void lsd(vector<string>& sVec) {const int N = 256+1;int w = sVec[0].length();int sz = sVec.size();for (int d = w-1; d >= 0; d--){vector<int> count(N, 0);vector<string> temp(N, "");for (int i = 0; i < sz; i++)count[sVec[i][d]+1]++;for (int i = 1; i < N; i++)count[i] += count[i-1];for (int i = 0; i < sz; i++){temp[count[sVec[i][d]]] = sVec[i];count[sVec[i][d]]++;}for (int i = 0; i < sz; i++)sVec[i] = temp[i]; } }int main() {//lsdstring s1[] = {"dab","add","cab","fab","fee","bad","dad","bee","fed","bed","ebb","ace"};vector<string> test1(s1, s1+sizeof(s1)/sizeof(string));msd(test1);for (auto r : test1)cout << r << endl; }下面是程序中的count計(jì)數(shù)方法:
vector sVec: aab, bba, baa。
計(jì)的是count[sVec[i][d]+1]++;所以計(jì)數(shù)如下:
| 0 | …… | ‘a(chǎn)’ | ‘b’ | ‘c’ |
|:----?:----?:----?:----?
| 0 | …… | 0 | 1 | 2 |
第一輪排序(即按第一個(gè)字符排序)按count數(shù)組將string放置到正確的位置:
aab放到[0],‘a(chǎn)’$\rightarrow1bba放到[1],′b′1 bba放到[1], 'b'1bba放到[1],′b′\rightarrow2baa放到[2],′b′2 baa放到[2], 'b'2baa放到[2],′b′\rightarrow$2
| 0 | …… | 1 | 3 | 2 |
……然后以這種方法分別對(duì)第2個(gè),第3個(gè)字符排序。
下面用msd的方法對(duì)一個(gè)字符串?dāng)?shù)組進(jìn)行按字典序排列。
桶排序
http://www.geeksforgeeks.org/bucket-sort-2/
#include <vector> #include <iostream> #include <algorithm>using namespace std;void bucket_sort(vector<double>& nums) {vector<vector<double>> bucket(10, vector<double>(0));for (auto num : nums)bucket[10*num].push_back(num);for (int i = 0; i < 10; i++)sort(bucket[i].begin(), bucket[i].end());int index = 0;//10個(gè)桶for (int i = 0; i < 10; i++){for (int j = 0; j < bucket[i].size(); j++) nums[index++] = bucket[i][j];} }int main() {double arr[] = {0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434};vector<double> test(arr, arr+sizeof(arr)/sizeof(double));bucket_sort(test);for (auto r : test)cout << r << " ";cout << endl; }對(duì)該算法簡(jiǎn)單分析,如果數(shù)據(jù)是期望平均分布的,則每個(gè)桶中的元素平均個(gè)數(shù)為N/M。如果對(duì)每個(gè)桶中的元素排序使用的算法是快速排序,每次排序的時(shí)間復(fù)雜度為O(N/Mlog(N/M))。則總的時(shí)間復(fù)雜度為O(N)+O(M)O(N/Mlog(N/M)) = O(N+ Nlog(N/M)) = O(N + NlogN - NlogM)。當(dāng)M接近于N是,桶排序的時(shí)間復(fù)雜度就可以近似認(rèn)為是O(N)的。就是桶越多,時(shí)間效率就越高,而桶越多,空間卻就越大,由此可見(jiàn)時(shí)間和空間是一個(gè)矛盾的兩個(gè)方面1。
1:https://www.byvoid.com/blog/sort-radix
平均復(fù)雜度為O(n)O(n)O(n):將元素放入桶中O(n)O(n)O(n),收集元素O(n)O(n)O(n),sort平均O(n)O(n)O(n)。
#reference
http://segmentfault.com/a/1190000003054515#articleHeader2
http://hxraid.iteye.com/blog/647759(桶排序效率分析)
https://www.cs.princeton.edu/~rs/AlgsDS07/18RadixSort.pdf(princeton radix sort)
http://segmentfault.com/a/1190000002595152 ?? ?? ?? ??
總結(jié)
以上是生活随笔為你收集整理的count sort, radix sort, bucket sort的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Union-find
- 下一篇: 【原创】“三次握手,四次挥手”你真的懂吗