日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

排序算法:桶排序、计数排序、基数排序

發(fā)布時(shí)間:2024/9/30 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 排序算法:桶排序、计数排序、基数排序 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

相關(guān)博客:

排序算法:冒泡排序、插入排序、選擇排序、希爾排序

排序算法:歸并排序、快速排序

排序算法:桶排序、計(jì)數(shù)排序、基數(shù)排序

排序算法:堆排序

十大排序算法小結(jié)


這篇博客將主要介紹三種時(shí)間復(fù)雜度是O(n)的排序算法:桶排序、計(jì)數(shù)排序、計(jì)數(shù)排序。因?yàn)檫@些排序算法的時(shí)間復(fù)雜度都是線性的,所以也把這類排序算法稱為線性排序。之所以能夠做到線性的時(shí)間復(fù)雜度,主要原因是這幾個(gè)算法是非基于比較的排序算法,不涉及元素之間的比較操作。

這幾種排序算法的時(shí)間復(fù)雜度雖然低,但是對要排序的數(shù)據(jù)要求比較苛刻,所以我們關(guān)鍵是要知道這些排序算法的適用場景


一、桶排序:

1、算法原理:

桶排序的核心思想就是將要排序的數(shù)據(jù)分到幾個(gè)有序的桶里,每個(gè)桶里的數(shù)據(jù)再單獨(dú)進(jìn)行排序。桶排序完之后,再把每個(gè)桶里的數(shù)據(jù)按照順序依次取出,組成的序列就是有序的了。

2、圖片演示:

3、桶排序的時(shí)間復(fù)雜度為O(n):

如果要排序的數(shù)據(jù)有 n 個(gè),我們把它們均勻地劃分到 m 個(gè)桶內(nèi),每個(gè)桶里就有 k=n/m 個(gè)元素。每個(gè)桶內(nèi)部使用歸并排序,時(shí)間復(fù)雜度為 O(k * logk)。m 個(gè)桶排序的時(shí)間復(fù)雜度就是 O(m * k * logk),因?yàn)?k=n/m,所以整個(gè)桶排序的時(shí)間復(fù)雜度就是 O(n*log(n/m))。當(dāng)桶的個(gè)數(shù)m 接近數(shù)據(jù)個(gè)數(shù) n 時(shí),log(n/m) 就是一個(gè)非常小的常量,這個(gè)時(shí)候桶排序的時(shí)間復(fù)雜度接近 O(n)。

所以,桶排序的時(shí)間復(fù)雜度,取決與對各個(gè)桶之間數(shù)據(jù)進(jìn)行排序的時(shí)間復(fù)雜度,桶劃分的越小,各個(gè)桶之間的數(shù)據(jù)越少,排序所用的時(shí)間也會越少,但相應(yīng)的空間消耗就會增大。?

4、桶排序的使用條件和適用場景:

桶排序?qū)σ判虻臄?shù)據(jù)的要求是非常苛刻的。使用條件如下:

(1)首先,要排序的數(shù)據(jù)需要很容易就能劃分成m個(gè)桶,并且,桶與桶之間有著天然的大小順序。這樣每個(gè)桶內(nèi)數(shù)據(jù)都排序完之后,桶與桶之間的數(shù)據(jù)不需要在進(jìn)行排序。

(2)其次,數(shù)據(jù)在各個(gè)桶之間的分布比較均勻的。如果數(shù)據(jù)經(jīng)過桶的劃分之后,有些桶里的數(shù)據(jù)非常多,有些非常少,很不平均,那桶內(nèi)數(shù)據(jù)排序的時(shí)間復(fù)雜度就不是常量級了。在極端情況下,如果數(shù)據(jù)都被劃分到一個(gè)桶里,那就退化為 O(nlogn) 的排序算法了。

所以,桶排序比較適合用在外部排序中。所謂的外部排序就是數(shù)據(jù)存儲在外部磁盤中,數(shù)據(jù)量比較大,內(nèi)存有限,無法將數(shù)據(jù)全部加載到內(nèi)存中。

5、應(yīng)用案例:

(1)需求描述:有10GB的訂單數(shù)據(jù),需按訂單金額(假設(shè)金額都是正整數(shù))進(jìn)行排序,但內(nèi)存有限,僅幾百M(fèi)B。

(2)解決思路:

掃描一遍文件,看訂單金額所處數(shù)據(jù)范圍,比如1元-10萬元,那么就分100個(gè)桶。

第一個(gè)桶存儲金額1-1000元之內(nèi)的訂單,第二個(gè)桶存1001-2000元之內(nèi)的訂單,依次類推。

每個(gè)桶對應(yīng)一個(gè)文件,并按照金額范圍的大小順序編號命名(00,01,02,…,99)。

將100個(gè)小文件依次放入內(nèi)存并用快排排序。

所有文件排好序后,只需按照文件編號從小到大依次讀取每個(gè)小文件并寫到大文件中即可。

注意點(diǎn):若單個(gè)文件無法全部載入內(nèi)存,則針對該文件繼續(xù)按照前面的思路進(jìn)行處理即可。


二、計(jì)數(shù)排序:

1、算法原理:

計(jì)數(shù)排序可以看成是桶排序的一種特殊情況,只是桶的大小粒度不一樣。當(dāng)要排序的 n 個(gè)數(shù)據(jù),所處的范圍并不大的時(shí)候,比如最大值是 k,我們就可以把數(shù)據(jù)劃分成 k 個(gè)桶。每個(gè)桶內(nèi)的數(shù)據(jù)值都是相同的,省掉了桶內(nèi)排序的時(shí)間。

2、適用場景:

計(jì)數(shù)排序只能用在數(shù)據(jù)范圍不大的場景中,如果數(shù)據(jù)范圍 k 比要排序的數(shù)據(jù) n 大很多,就不適合用計(jì)數(shù)排序了。而且,計(jì)數(shù)排序只能給非負(fù)整數(shù)排序,如果要排序的數(shù)據(jù)是其他類型的,要將其在不改變相對大小的情況下,轉(zhuǎn)化為非負(fù)整數(shù)。

3、動圖演示:

4、算法描述:

(1)找出待排序的數(shù)組中最大和最小的元素;

(2)統(tǒng)計(jì)數(shù)組中每個(gè)值為i的元素出現(xiàn)的次數(shù),存入數(shù)組C的第i項(xiàng);

(3)對所有的計(jì)數(shù)累加(從C中的第一個(gè)元素開始,每一項(xiàng)和前一項(xiàng)相加);

(4)反向填充目標(biāo)數(shù)組:將每個(gè)元素i放在新數(shù)組的第C(i)項(xiàng),每放一個(gè)元素就將C(i)減去1。

5、應(yīng)用案例:

(1)假設(shè)只有8個(gè)考生分?jǐn)?shù)在0-5分之間,成績存于數(shù)組A[8] = [2,5,3,0,2,3,0,3]。

使用大小為6的數(shù)組C[6]表示桶,下標(biāo)對應(yīng)分?jǐn)?shù),即0,1,2,3,4,5。

C[6]存儲的是考生人數(shù),只需遍歷一邊考生分?jǐn)?shù),就可以得到C[6] = [2,0,2,3,0,1]。

對C[6]數(shù)組順序求和則C[6]=[2,2,4,7,7,8],C[k]存儲的是小于等于分?jǐn)?shù)k的考生個(gè)數(shù)。

(2)數(shù)組R[8] = [0,0,2,2,3,3,3,5]存儲考生名次。那么如何得到R[8]的呢?

從后到前依次掃描數(shù)組A,比如掃描到3時(shí),可以從數(shù)組C中取出下標(biāo)為3的值7,也就是說,到目前為止,包括自己在內(nèi),分?jǐn)?shù)小于等于3的考生有7個(gè),也就是說3是數(shù)組R的第7個(gè)元素(也就是數(shù)組R中下標(biāo)為6的位置)。當(dāng)3放入數(shù)組R后,小于等于3的元素就剩下6個(gè)了,相應(yīng)的C[3]要減1變成6。

以此類推,當(dāng)掃描到第二個(gè)分?jǐn)?shù)為3的考生時(shí),就會把它放入數(shù)組R中第6個(gè)元素的位置(也就是下標(biāo)為5的位置)。當(dāng)掃描完數(shù)組A后,數(shù)組R內(nèi)的數(shù)據(jù)就是按照分?jǐn)?shù)從小到大排列的了。

6、Java代碼實(shí)現(xiàn):

public class CountingSort {public void countingSort(int[] a){int len = a.length;if(len<=1) return;//1、查找數(shù)組中數(shù)據(jù)的范圍int max = a[0];for(int i=1;i<len;i++){if(max<a[i]) max=a[i];}//2、申請一個(gè)數(shù)組cint[] c = new int[max+1]; //3、遍歷數(shù)組,計(jì)算每個(gè)元素的個(gè)數(shù),放入c中。for(int i=0;i<len;i++)c[a[i]]++;//4、依次累加for(int i=1;i<=max;i++)c[i]=c[i-1]+c[i];//5、申請一個(gè)臨時(shí)數(shù)組,存儲排序后的結(jié)果,并反向填充。int[] r = new int[len];//計(jì)數(shù)排序的關(guān)鍵步驟,參照上圖:for(int i=len-1;i>=0;i--){int index = c[a[i]]-1;r[index] = a[i];c[a[i]]--;}//6、將結(jié)果拷貝回原數(shù)組for(int i=0;i<len;i++)a[i]=r[i];} }

7、算法分析:

計(jì)數(shù)排序是一個(gè)穩(wěn)定的排序算法。當(dāng)輸入的元素是 n 個(gè) 0到 k 之間的整數(shù)時(shí),時(shí)間復(fù)雜度是O(n+k),空間復(fù)雜度也是O(n+k),其排序速度快于任何比較排序算法。當(dāng)k不是很大并且序列比較集中時(shí),計(jì)數(shù)排序是一個(gè)很有效的排序算法。


三、基數(shù)排序:

1、算法原理:

基數(shù)排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次類推,直到最高位。有時(shí)候有些屬性是有優(yōu)先級順序的,先按低優(yōu)先級排序,再按高優(yōu)先級排序。最后的次序就是高優(yōu)先級高的在前,高優(yōu)先級相同的低優(yōu)先級高的在前。

2、使用條件:

基數(shù)排序?qū)σ判虻臄?shù)據(jù)是有要求的,需要可以分割出獨(dú)立的“位”來比較,而且位之間有遞進(jìn)的關(guān)系,如果 a 數(shù)據(jù)的高位比 b數(shù)據(jù)大,那剩下的低位就不用比較了。除此之外,每一位的數(shù)據(jù)范圍不能太大,因?yàn)榛鶖?shù)要借助桶排序或者計(jì)數(shù)排序算法來排序,否則,基數(shù)排序的時(shí)間復(fù)雜度就無法做到 O(n) 了。

3、動圖演示:

(1)得數(shù)組中的最大數(shù),并取得位數(shù);

(2)arr為原始數(shù)組,從最低位開始取每個(gè)位組成radix數(shù)組;

(3)對radix進(jìn)行計(jì)數(shù)排序(利用計(jì)數(shù)排序適用于小范圍數(shù)的特點(diǎn));

4、算法分析:

(1)基數(shù)排序基于分別排序,分別收集,所以是穩(wěn)定的。

(2)如果要排序的數(shù)據(jù)有 k 位,那我們就需要 k 次桶排序或者計(jì)數(shù)排序,總的時(shí)間復(fù)雜度是 O(k*n)。當(dāng) k 不大的時(shí)候,當(dāng) k 不大的時(shí)候,比如手機(jī)號碼排序的例子,k 最大就是 11,所以基數(shù)排序的時(shí)間復(fù)雜度就近似于 O(n)。

(3)基數(shù)排序的空間復(fù)雜度為O(n+k),其中k為桶的數(shù)量。一般來說n>>k,因此額外空間需要大概n個(gè)左右。

5、應(yīng)用案例:

需求:排序10萬個(gè)手機(jī)號:

(1)比較兩個(gè)手機(jī)號碼a,b的大小,如果在前面幾位中a已經(jīng)比b大了,那后面幾位就不用看了。但是這種排序不穩(wěn)定。

(2)借助穩(wěn)定排序算法的思想,可以先按照最后一位來排序手機(jī)號碼,然后再按照倒數(shù)第二位來重新排序,以此類推,最后按照第一個(gè)位重新排序。

(3)經(jīng)過11次排序后,手機(jī)號碼就變?yōu)橛行虻牧恕?/p>

(4)每次排序有序數(shù)據(jù)范圍較小,可以使用桶排序或計(jì)數(shù)排序來完成。

?

?

本篇博客主要參考《極客時(shí)間》王爭的《數(shù)據(jù)結(jié)構(gòu)與算法之美》專欄第13節(jié)。

總結(jié)

以上是生活随笔為你收集整理的排序算法:桶排序、计数排序、基数排序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。