RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

常用的非比較排序算法:計數(shù)排序,基數(shù)排序,桶排序的詳細(xì)資料概述

Linux愛好者 ? 來源:未知 ? 作者:易水寒 ? 2018-06-18 15:11 ? 次閱讀

這篇文章中我們來探討一下常用的非比較排序算法:計數(shù)排序,基數(shù)排序,桶排序。在一定條件下,它們的時間復(fù)雜度可以達(dá)到O(n)。

這里我們用到的唯一數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,當(dāng)然我們也可以利用鏈表來實(shí)現(xiàn)下述算法。

計數(shù)排序(Counting Sort)

計數(shù)排序用到一個額外的計數(shù)數(shù)組C,根據(jù)數(shù)組C來將原數(shù)組A中的元素排到正確的位置。

通俗地理解,例如有10個年齡不同的人,假如統(tǒng)計出有8個人的年齡不比小明大(即小于等于小明的年齡,這里也包括了小明),那么小明的年齡就排在第8位,通過這種思想可以確定每個人的位置,也就排好了序。當(dāng)然,年齡一樣時需要特殊處理(保證穩(wěn)定性):通過反向填充目標(biāo)數(shù)組,填充完畢后將對應(yīng)的數(shù)字統(tǒng)計遞減,可以確保計數(shù)排序的穩(wěn)定性。

計數(shù)排序的步驟如下:

統(tǒng)計數(shù)組A中每個值A(chǔ)[i]出現(xiàn)的次數(shù),存入C[A[i]]

從前向后,使數(shù)組C中的每個值等于其與前一項(xiàng)相加,這樣數(shù)組C[A[i]]就變成了代表數(shù)組A中小于等于A[i]的元素個數(shù)

反向填充目標(biāo)數(shù)組B:將數(shù)組元素A[i]放在數(shù)組B的第C[A[i]]個位置(下標(biāo)為C[A[i]] – 1),每放一個元素就將C[A[i]]遞減

計數(shù)排序的實(shí)現(xiàn)代碼如下:

#include

usingnamespacestd;

// 分類 ------------ 內(nèi)部非比較排序

// 數(shù)據(jù)結(jié)構(gòu) --------- 數(shù)組

// 最差時間復(fù)雜度 ---- O(n + k)

// 最優(yōu)時間復(fù)雜度 ---- O(n + k)

// 平均時間復(fù)雜度 ---- O(n + k)

// 所需輔助空間 ------ O(n + k)

// 穩(wěn)定性 ----------- 穩(wěn)定

constintk=100;// 基數(shù)為100,排序[0,99]內(nèi)的整數(shù)

intC[k];// 計數(shù)數(shù)組

voidCountingSort(intA[],intn)

{

for(inti=0;i

{

C[i]=0;

}

for(inti=0;i

{

C[A[i]]++;

}

for(inti=1;i

{

C[i]=C[i]+C[i-1];

}

int*B=(int*)malloc((n)*sizeof(int));// 分配臨時空間,長度為n,用來暫存中間數(shù)據(jù)

for(inti=n-1;i>=0;i--)// 從后向前掃描保證計數(shù)排序的穩(wěn)定性(重復(fù)元素相對次序不變)

{

B[--C[A[i]]]=A[i];// 把每個元素A[i]放到它在輸出數(shù)組B中的正確位置上

// 當(dāng)再遇到重復(fù)元素時會被放在當(dāng)前元素的前一個位置上保證計數(shù)排序的穩(wěn)定性

}

for(inti=0;i

{

A[i]=B[i];

}

free(B);// 釋放臨時空間

}

intmain()

{

intA[]={15,22,19,46,27,73,1,19,8};// 針對計數(shù)排序設(shè)計的輸入,每一個元素都在[0,100]上且有重復(fù)元素

intn=sizeof(A)/sizeof(int);

CountingSort(A,n);

printf("計數(shù)排序結(jié)果:");

for(inti=0;i

{

printf("%d ",A[i]);

}

printf("\n");

return0;

}

下圖給出了對{ 4, 1, 3, 4, 3 }進(jìn)行計數(shù)排序的簡單演示過程

常用的非比較排序算法:計數(shù)排序,基數(shù)排序,桶排序的詳細(xì)資料概述

計數(shù)排序的時間復(fù)雜度和空間復(fù)雜度與數(shù)組A的數(shù)據(jù)范圍(A中元素的最大值與最小值的差加上1)有關(guān),因此對于數(shù)據(jù)范圍很大的數(shù)組,計數(shù)排序需要大量時間和內(nèi)存。

例如:對0到99之間的數(shù)字進(jìn)行排序,計數(shù)排序是最好的算法,然而計數(shù)排序并不適合按字母順序排序人名,將計數(shù)排序用在基數(shù)排序算法中,能夠更有效的排序數(shù)據(jù)范圍很大的數(shù)組。

基數(shù)排序(Radix Sort)

基數(shù)排序的發(fā)明可以追溯到1887年赫爾曼·何樂禮在打孔卡片制表機(jī)上的貢獻(xiàn)。它是這樣實(shí)現(xiàn)的:將所有待比較正整數(shù)統(tǒng)一為同樣的數(shù)位長度,數(shù)位較短的數(shù)前面補(bǔ)零。然后,從最低位開始進(jìn)行基數(shù)為10的計數(shù)排序,一直到最高位計數(shù)排序完后,數(shù)列就變成一個有序序列(利用了計數(shù)排序的穩(wěn)定性)。

基數(shù)排序的實(shí)現(xiàn)代碼如下:

#include

usingnamespacestd;

// 分類 ------------- 內(nèi)部非比較排序

// 數(shù)據(jù)結(jié)構(gòu) ---------- 數(shù)組

// 最差時間復(fù)雜度 ---- O(n * dn)

// 最優(yōu)時間復(fù)雜度 ---- O(n * dn)

// 平均時間復(fù)雜度 ---- O(n * dn)

// 所需輔助空間 ------ O(n * dn)

// 穩(wěn)定性 ----------- 穩(wěn)定

constintdn=3;// 待排序的元素為三位數(shù)及以下

constintk=10;// 基數(shù)為10,每一位的數(shù)字都是[0,9]內(nèi)的整數(shù)

intC[k];

intGetDigit(intx,intd)// 獲得元素x的第d位數(shù)字

{

intradix[]={1,1,10,100};// 最大為三位數(shù),所以這里只要到百位就滿足了

return(x/radix[d])%10;

}

voidCountingSort(intA[],intn,intd)// 依據(jù)元素的第d位數(shù)字,對A數(shù)組進(jìn)行計數(shù)排序

{

for(inti=0;i

{

C[i]=0;

}

for(inti=0;i

{

C[GetDigit(A[i],d)]++;

}

for(inti=1;i

{

C[i]=C[i]+C[i-1];

}

int*B=(int*)malloc(n *sizeof(int));

for(inti=n-1;i>=0;i--)

{

intdight=GetDigit(A[i],d);// 元素A[i]當(dāng)前位數(shù)字為dight

B[--C[dight]]=A[i];// 根據(jù)當(dāng)前位數(shù)字,把每個元素A[i]放到它在輸出數(shù)組B中的正確位置上

// 當(dāng)再遇到當(dāng)前位數(shù)字同為dight的元素時,會將其放在當(dāng)前元素的前一個位置上保證計數(shù)排序的穩(wěn)定性

}

for(inti=0;i

{

A[i]=B[i];

}

free(B);

}

voidLsdRadixSort(intA[],intn)// 最低位優(yōu)先基數(shù)排序

{

for(intd=1;d<=?dn;d++)?????// 從低位到高位

CountingSort(A,n,d);// 依據(jù)第d位數(shù)字對A進(jìn)行計數(shù)排序

}

intmain()

{

intA[]={20,90,64,289,998,365,852,123,789,456};// 針對基數(shù)排序設(shè)計的輸入

intn=sizeof(A)/sizeof(int);

LsdRadixSort(A,n);

printf("基數(shù)排序結(jié)果:");

for(inti=0;i

{

printf("%d ",A[i]);

}

printf("\n");

return0;

}

下圖給出了對{ 329, 457, 657, 839, 436, 720, 355 }進(jìn)行基數(shù)排序的簡單演示過程

常用的非比較排序算法:計數(shù)排序,基數(shù)排序,桶排序的詳細(xì)資料概述

基數(shù)排序的時間復(fù)雜度是O(n*dn),其中n是待排序元素個數(shù),dn是數(shù)字位數(shù)。這個時間復(fù)雜度不一定優(yōu)于O(n log n),dn的大小取決于數(shù)字位的選擇(比如比特位數(shù)),和待排序數(shù)據(jù)所屬數(shù)據(jù)類型的全集的大?。籨n決定了進(jìn)行多少輪處理,而n是每輪處理的操作數(shù)目。

如果考慮和比較排序進(jìn)行對照,基數(shù)排序的形式復(fù)雜度雖然不一定更小,但由于不進(jìn)行比較,因此其基本操作的代價較小,而且如果適當(dāng)?shù)倪x擇基數(shù),dn一般不大于log n,所以基數(shù)排序一般要快過基于比較的排序,比如快速排序。由于整數(shù)也可以表達(dá)字符串(比如名字或日期)和特定格式的浮點(diǎn)數(shù),所以基數(shù)排序并不是只能用于整數(shù)排序。

桶排序(Bucket Sort)

桶排序也叫箱排序。工作的原理是將數(shù)組元素映射到有限數(shù)量個桶里,利用計數(shù)排序可以定位桶的邊界,每個桶再各自進(jìn)行桶內(nèi)排序(使用其它排序算法或以遞歸方式繼續(xù)使用桶排序)。

桶排序的實(shí)現(xiàn)代碼如下:

#include

usingnamespacestd;

// 分類 ------------- 內(nèi)部非比較排序

// 數(shù)據(jù)結(jié)構(gòu) --------- 數(shù)組

// 最差時間復(fù)雜度 ---- O(nlogn)或O(n^2),只有一個桶,取決于桶內(nèi)排序方式

// 最優(yōu)時間復(fù)雜度 ---- O(n),每個元素占一個桶

// 平均時間復(fù)雜度 ---- O(n),保證各個桶內(nèi)元素個數(shù)均勻即可

// 所需輔助空間 ------ O(n + bn)

// 穩(wěn)定性 ----------- 穩(wěn)定

/* 本程序用數(shù)組模擬桶 */

constintbn=5;// 這里排序[0,49]的元素,使用5個桶就夠了,也可以根據(jù)輸入動態(tài)確定桶的數(shù)量

intC[bn];// 計數(shù)數(shù)組,存放桶的邊界信息

voidInsertionSort(intA[],intleft,intright)

{

for(inti=left+1;i<=?right;i++)??// 從第二張牌開始抓,直到最后一張牌

{

intget=A[i];

intj=i-1;

while(j>=left&&A[j]>get)

{

A[j+1]=A[j];

j--;

}

A[j+1]=get;

}

}

intMapToBucket(intx)

{

returnx/10;// 映射函數(shù)f(x),作用相當(dāng)于快排中的Partition,把大量數(shù)據(jù)分割成基本有序的數(shù)據(jù)塊

}

voidCountingSort(intA[],intn)

{

for(inti=0;i

{

C[i]=0;

}

for(inti=0;i

{

C[MapToBucket(A[i])]++;

}

for(inti=1;i

{

C[i]=C[i]+C[i-1];

}

int*B=(int*)malloc((n)*sizeof(int));

for(inti=n-1;i>=0;i--)// 從后向前掃描保證計數(shù)排序的穩(wěn)定性(重復(fù)元素相對次序不變)

{

intb=MapToBucket(A[i]);// 元素A[i]位于b號桶

B[--C[b]]=A[i];// 把每個元素A[i]放到它在輸出數(shù)組B中的正確位置上

// 桶的邊界被更新:C[b]為b號桶第一個元素的位置

}

for(inti=0;i

{

A[i]=B[i];

}

free(B);

}

voidBucketSort(intA[],intn)

{

CountingSort(A,n);// 利用計數(shù)排序確定各個桶的邊界(分桶)

for(inti=0;i

{

intleft=C[i];// C[i]為i號桶第一個元素的位置

intright=(i==bn-1?n-1:C[i+1]-1);// C[i+1]-1為i號桶最后一個元素的位置

if(left

InsertionSort(A,left,right);

}

}

intmain()

{

intA[]={29,25,3,49,9,37,21,43};// 針對桶排序設(shè)計的輸入

intn=sizeof(A)/sizeof(int);

BucketSort(A,n);

printf("桶排序結(jié)果:");

for(inti=0;i

{

printf("%d ",A[i]);

}

printf("\n");

return0;

}

下圖給出了對{ 29, 25, 3, 49, 9, 37, 21, 43 }進(jìn)行桶排序的簡單演示過程

常用的非比較排序算法:計數(shù)排序,基數(shù)排序,桶排序的詳細(xì)資料概述

桶排序不是比較排序,不受到O(nlogn)下限的影響,它是鴿巢排序的一種歸納結(jié)果,當(dāng)所要排序的數(shù)組值分散均勻的時候,桶排序擁有線性的時間復(fù)雜度。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    40121
  • 排序算法
    +關(guān)注

    關(guān)注

    0

    文章

    52

    瀏覽量

    10056
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    417

    瀏覽量

    25939

原文標(biāo)題:常用排序算法總結(jié)(2)

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    FPGA排序-冒泡排序介紹

    排序算法是圖像處理中經(jīng)常使用一種算法,常見的排序算法有插入排序、希爾
    發(fā)表于 07-17 10:12 ?1081次閱讀
    FPGA<b class='flag-5'>排序</b>-冒泡<b class='flag-5'>排序</b>介紹

    嵌入式stm32實(shí)用的排序算法 - 交換排序

    一次不能容納全部的排序記錄,在排序過程中需要訪問外存。內(nèi)部排序高速、有效,是我們比較常用排序
    發(fā)表于 04-12 13:14

    資料下載:基數(shù)排序:*** 與 MSD

    1.算法原理基數(shù)排序是通過“分配”和“收集”過程來實(shí)現(xiàn)排序。1)分配,先從個位開始,根據(jù)位值(0-9)分別放到0~9號中(比如53,個位為3,則放入3號
    發(fā)表于 07-05 07:57

    算法的原理是什么?基數(shù)排序是如何實(shí)現(xiàn)的?

    算法的原理是什么?基數(shù)排序是如何實(shí)現(xiàn)的?有哪幾種方法可以實(shí)現(xiàn)基數(shù)排序?
    發(fā)表于 07-05 07:42

    各種排序算法的時間空間復(fù)雜度、穩(wěn)定性

    各種排序算法的時間空間復(fù)雜度、穩(wěn)定性一、排序算法分類:二、排序算法
    發(fā)表于 12-21 07:48

    C語言教程之幾種排序算法

    數(shù)據(jù)結(jié)構(gòu)的排序算法有很多種。 其中, 快速排序 、希爾排序、堆排序、直接選擇排序不是穩(wěn)定的
    發(fā)表于 11-16 10:23 ?1759次閱讀

    基數(shù)排序是怎么排的_基數(shù)排序詳細(xì)過程

    基數(shù)排序詳細(xì)過程如下文所述。基數(shù)排序最初是用在打孔卡片制表機(jī)上的一種排序算法,基數(shù)排序從最低為開
    的頭像 發(fā)表于 02-05 14:11 ?1.7w次閱讀
    <b class='flag-5'>基數(shù)排序</b>是怎么排的_<b class='flag-5'>基數(shù)排序</b><b class='flag-5'>詳細(xì)</b>過程

    基數(shù)排序知識點(diǎn)全面概括

    本文是對基數(shù)排序的全面概括。基數(shù)排序中,我們不能再只用一位數(shù)的序列來列舉示例了。一位數(shù)的序列對基數(shù)排序來說就是一個計數(shù)排序
    的頭像 發(fā)表于 02-05 14:30 ?2398次閱讀
    <b class='flag-5'>基數(shù)排序</b>知識點(diǎn)全面概括

    基數(shù)排序 java代碼實(shí)現(xiàn)

    本文詳細(xì)概括了基數(shù)排序以及java代碼實(shí)現(xiàn)。基數(shù)排序又稱排序,相對于常見的比較
    發(fā)表于 02-05 14:46 ?996次閱讀
    <b class='flag-5'>基數(shù)排序</b> java代碼實(shí)現(xiàn)

    C語言實(shí)現(xiàn)簡單的基數(shù)排序

    本文主要闡述的類容是C語言實(shí)現(xiàn)簡單的基數(shù)排序。基數(shù)排序是一種分配排序,其基本思想是:排序過程無須比較關(guān)鍵字,而是通過“分配”和“收集”過程來
    發(fā)表于 02-05 14:57 ?1785次閱讀
    C語言實(shí)現(xiàn)簡單的<b class='flag-5'>基數(shù)排序</b>

    常用排序算法總覽

    我們通常所說的排序算法往往指的是內(nèi)部排序算法,即數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序。
    的頭像 發(fā)表于 06-13 18:18 ?2828次閱讀
    <b class='flag-5'>常用</b>的<b class='flag-5'>排序</b><b class='flag-5'>算法</b>總覽

    常用排序算法分析

    一種是比較排序,時間復(fù)雜度O(nlogn) ~ O(n^2),主要有:冒泡排序,選擇排序,插入排序,歸并
    的頭像 發(fā)表于 07-13 16:13 ?2157次閱讀

    實(shí)用的排序算法 - 交換排序

    實(shí)用的排序算法 - 交換排序
    的頭像 發(fā)表于 03-20 09:53 ?1738次閱讀
    實(shí)用的<b class='flag-5'>排序</b><b class='flag-5'>算法</b> -  交換<b class='flag-5'>排序</b>

    排序算法分享:歸并排序說明

    我們今天繼續(xù)給大家分享排序算法里面的另外一種排序算法:歸并排序!
    的頭像 發(fā)表于 12-24 14:34 ?769次閱讀

    常見排序算法分類

    (nlogn),因此也稱為非線性時間比較排序。 非比較排序:不通過比較來決定元素間的相對次序,它可以突破基于
    的頭像 發(fā)表于 06-22 14:49 ?906次閱讀
    常見<b class='flag-5'>排序</b><b class='flag-5'>算法</b>分類
    RM新时代网站-首页