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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

计数排序、桶排序和基数排序

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

計(jì)數(shù)排序

當(dāng)輸入的元素是 n 個(gè) 0 到 k 之間的整數(shù)時(shí),它的運(yùn)行時(shí)間是 Θ(n?+?k)。計(jì)數(shù)排序不是比較排序,排序的速度快于任何比較排序算法。

由于用來(lái)計(jì)數(shù)的數(shù)組C的長(zhǎng)度取決于待排序數(shù)組中數(shù)據(jù)的范圍(等于待排序數(shù)組的最大值與最小值的差加上1),這使得計(jì)數(shù)排序?qū)τ跀?shù)據(jù)范圍很大的數(shù)組,需要大量時(shí)間和內(nèi)存。例如:計(jì)數(shù)排序是用來(lái)排序0到100之間的數(shù)字的最好的算法,但是它不適合按字母順序排序人名。但是,計(jì)數(shù)排序可以用在基數(shù)排序中的算法來(lái)排序數(shù)據(jù)范圍很大的數(shù)組。

算法的步驟如下:

  • 找出待排序的數(shù)組中最大和最小的元素
  • 統(tǒng)計(jì)數(shù)組中每個(gè)值為i的元素出現(xiàn)的次數(shù),存入數(shù)組C的第i項(xiàng)
  • 對(duì)所有的計(jì)數(shù)累加(從C中的第一個(gè)元素開(kāi)始,每一項(xiàng)和前一項(xiàng)相加)
  • 反向填充目標(biāo)數(shù)組:將每個(gè)元素i放在新數(shù)組的第C(i)項(xiàng),每放一個(gè)元素就將C(i)減去1
  • 貼上代碼:

    [html] view plaincopyprint?
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<time.h>??
  • ??
  • //對(duì)于排序的關(guān)鍵字范圍,一定是0-99??
  • #define?NUM_RANGE?(100)??
  • ??
  • void?print_arr(int?*arr,?int?n)??
  • {??
  • ???????int?i;??
  • ???????for(i=0;?i<n;?i++){??
  • ???????????????if(!i){??
  • ???????????????????????printf(“%d”,?arr[i]);??
  • ???????????????}else{??
  • ???????????????????????printf(“?%d”,?arr[i]);??
  • ???????????????}??
  • ???????}??
  • ???????printf(“\n”);??
  • }??
  • ??
  • /*??
  • 算法的步驟如下:??
  • ????1.找出待排序的數(shù)組中最大和最小的元素??
  • ????2.統(tǒng)計(jì)數(shù)組中每個(gè)值為i的元素出現(xiàn)的次數(shù),存入數(shù)組C的第i項(xiàng)??
  • ????3.對(duì)所有的計(jì)數(shù)累加(從C中的第一個(gè)元素開(kāi)始,每一項(xiàng)和前一項(xiàng)相加)??
  • ????4.反向填充目標(biāo)數(shù)組:將每個(gè)元素i放在新數(shù)組的第C(i)項(xiàng),每放一個(gè)元素就將C(i)減去1??
  • */??
  • ??
  • void?counting_sort(int?*ini_arr,?int?*sorted_arr,?int?n)??
  • {??
  • ???????int?*count_arr?=?(int?*)malloc(sizeof(int)?*?NUM_RANGE);??
  • ???????int?i,?j,?k;??
  • ??
  • ???????//統(tǒng)計(jì)數(shù)組中,每個(gè)元素出現(xiàn)的次數(shù)??
  • ???????for(k=0;?k<NUM_RANGE;?k++){??
  • ???????????????count_arr[k]?=?0;??
  • ???????}??
  • ?????????
  • ???????for(i=0;?i<n;?i++){??
  • ???????????????count_arr[ini_arr[i]]++;??
  • ???????}??
  • ??
  • ??
  • ???????for(k=1;?k<NUM_RANGE;?k++){??
  • ???????????????count_arr[k]?+=?count_arr[k-1];??
  • ???????}??
  • ??
  • ???????for(j=n-1?;?j>=0;?j–){??
  • ???????????int?elem?=?ini_arr[j];??
  • ???????????int?index?=?count_arr[elem]-1;??
  • ???????????sorted_arr[index]?=?elem;??
  • ???????????count_arr[elem]–;??
  • ???????}??
  • ???????free(count_arr);??
  • }??
  • ??
  • ??
  • int?main(int?argc,?char*?argv[])??
  • {??
  • ???????int?n;??
  • ???????if(argc?<?2){??
  • ???????????????n?=?10;??
  • ???????}else{??
  • ???????????????n?=?atoi(argv[1]);??
  • ???????}??
  • ???????int?i;??
  • ???????int?*arr?=?(int?*)malloc(sizeof(int)?*?n);??
  • ???????int?*sorted_arr?=?(int?*)malloc(sizeof(int)?*n);??
  • ???????srand(time(0));??
  • ??
  • ?????????
  • ???????for(i=0;?i<n;?i++){??
  • ???????????????arr[i]?=?rand()?%?NUM_RANGE;??
  • ???????}??
  • ??
  • ???????printf(“ini_array:?”);??
  • ???????print_arr(arr,?n);??
  • ???????counting_sort(arr,?sorted_arr,?n);??
  • ???????printf(“sorted_array:?”);??
  • ???????print_arr(sorted_arr,?n);??
  • ???????free(arr);??
  • ???????free(sorted_arr);??
  • ???????return?0;??
  • }??
  • #include <stdio.h> #include <stdlib.h> #include <time.h> //對(duì)于排序的關(guān)鍵字范圍,一定是0-99 #define NUM_RANGE (100) void print_arr(int *arr, int n) { int i; for(i=0; i<n; i++){ if(!i){ printf("%d", arr[i]); }else{ printf(" %d", arr[i]); } } printf("\n"); } /* 算法的步驟如下: 1.找出待排序的數(shù)組中最大和最小的元素 2.統(tǒng)計(jì)數(shù)組中每個(gè)值為i的元素出現(xiàn)的次數(shù),存入數(shù)組C的第i項(xiàng) 3.對(duì)所有的計(jì)數(shù)累加(從C中的第一個(gè)元素開(kāi)始,每一項(xiàng)和前一項(xiàng)相加) 4.反向填充目標(biāo)數(shù)組:將每個(gè)元素i放在新數(shù)組的第C(i)項(xiàng),每放一個(gè)元素就將C(i)減去1 */ void counting_sort(int *ini_arr, int *sorted_arr, int n) { int *count_arr = (int *)malloc(sizeof(int) * NUM_RANGE); int i, j, k; //統(tǒng)計(jì)數(shù)組中,每個(gè)元素出現(xiàn)的次數(shù) for(k=0; k<NUM_RANGE; k++){ count_arr[k] = 0; } for(i=0; i<n; i++){ count_arr[ini_arr[i]]++; } for(k=1; k<NUM_RANGE; k++){ count_arr[k] += count_arr[k-1]; } for(j=n-1 ; j>=0; j--){ int elem = ini_arr[j]; int index = count_arr[elem]-1; sorted_arr[index] = elem; count_arr[elem]--; } free(count_arr); } int main(int argc, char* argv[]) { int n; if(argc < 2){ n = 10; }else{ n = atoi(argv[1]); } int i; int *arr = (int *)malloc(sizeof(int) * n); int *sorted_arr = (int *)malloc(sizeof(int) *n); srand(time(0)); for(i=0; i<n; i++){ arr[i] = rand() % NUM_RANGE; } printf("ini_array: "); print_arr(arr, n); counting_sort(arr, sorted_arr, n); printf("sorted_array: "); print_arr(sorted_arr, n); free(arr); free(sorted_arr); return 0; }


    ?桶排序:http://blog.sina.com.cn/s/blog_667739ba0100veth.html

    桶排序的基本思想

    假設(shè)有一組長(zhǎng)度為N的待排關(guān)鍵字序列K[1….n]。首先將這個(gè)序列劃分成M個(gè)的子區(qū)間(桶) 。然后基于某種映射函數(shù) ,將待排序列的關(guān)鍵字k映射到第i個(gè)桶中(即桶數(shù)組B的下標(biāo) i) ,那么該關(guān)鍵字k就作為B[i]中的元素(每個(gè)桶B[i]都是一組大小為N/M的序列)。接著對(duì)每個(gè)桶B[i]中的所有元素進(jìn)行比較排序(可以使用快排)。然后依次枚舉輸出B[0]….B[M]中的全部?jī)?nèi)容即是一個(gè)有序序列。

    假如待排序列K= {49、 38 、 35、 97 、 76、 73 、 27、 49 }。這些數(shù)據(jù)全部在1—100之間。因此我們定制10個(gè)桶,然后確定映射函數(shù)f(k)=k/10。則第一個(gè)關(guān)鍵字49將定位到第4個(gè)桶中(49/10=4)。依次將所有關(guān)鍵字全部堆入桶中,并在每個(gè)非空的桶中進(jìn)行快速排序。

    桶排序代價(jià)分析

    桶排序利用函數(shù)的映射關(guān)系,減少了幾乎所有的比較工作。實(shí)際上,桶排序的f(k)值的計(jì)算,其作用就相當(dāng)于快排中劃分,已經(jīng)把大量數(shù)據(jù)分割成了基本有序的數(shù)據(jù)塊(桶)。然后只需要對(duì)桶中的少量數(shù)據(jù)做先進(jìn)的比較排序即可。

    ?

    對(duì)N個(gè)關(guān)鍵字進(jìn)行桶排序的時(shí)間復(fù)雜度分為兩個(gè)部分:

    (1)?循環(huán)計(jì)算每個(gè)關(guān)鍵字的桶映射函數(shù),這個(gè)時(shí)間復(fù)雜度是O(N)。

    (2) 利用先進(jìn)的比較排序算法對(duì)每個(gè)桶內(nèi)的所有數(shù)據(jù)進(jìn)行排序,其時(shí)間復(fù)雜度為 ∑ O(Ni*logNi) 。其中Ni 為第i個(gè)桶的數(shù)據(jù)量。

    ?

    很顯然,第(2)部分是桶排序性能好壞的決定因素。盡量減少桶內(nèi)數(shù)據(jù)的數(shù)量是提高效率的唯一辦法(因?yàn)榛诒容^排序的最好平均時(shí)間復(fù)雜度只能達(dá)到O(N*logN)了)。因此,我們需要盡量做到下面兩點(diǎn):

    (1) 映射函數(shù)f(k)能夠?qū)個(gè)數(shù)據(jù)平均的分配到M個(gè)桶中,這樣每個(gè)桶就有[N/M]個(gè)數(shù)據(jù)量。

    (2) 盡量的增大桶的數(shù)量。極限情況下每個(gè)桶只能得到一個(gè)數(shù)據(jù),這樣就完全避開(kāi)了桶內(nèi)數(shù)據(jù)的“比較”排序操作。 當(dāng)然,做到這一點(diǎn)很不容易,數(shù)據(jù)量巨大的情況下,f(k)函數(shù)會(huì)使得桶集合的數(shù)量巨大,空間浪費(fèi)嚴(yán)重。這就是一個(gè)時(shí)間代價(jià)和空間代價(jià)的權(quán)衡問(wèn)題了。

    ?

    對(duì)于N個(gè)待排數(shù)據(jù),M個(gè)桶,平均每個(gè)桶[N/M]個(gè)數(shù)據(jù)的桶排序平均時(shí)間復(fù)雜度為:

    O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)

    當(dāng)N=M時(shí),即極限情況下每個(gè)桶只有一個(gè)數(shù)據(jù)時(shí)。桶排序的最好效率能夠達(dá)到O(N)。

    ?

    總結(jié): 桶排序的平均時(shí)間復(fù)雜度為線性的O(N+C),其中C=N*(logN-logM)。如果相對(duì)于同樣的N,桶數(shù)量M越大,其效率越高,最好的時(shí)間復(fù)雜度達(dá)到O(N)。 當(dāng)然桶排序的空間復(fù)雜度 為O(N+M),如果輸入數(shù)據(jù)非常龐大,而桶的數(shù)量也非常多,則空間代價(jià)無(wú)疑是昂貴的。此外,桶排序是穩(wěn)定的。

    我個(gè)人還有一個(gè)感受:在查找算法中,基于比較的查找算法最好的時(shí)間復(fù)雜度也是O(logN)。比如折半查找、平衡二叉樹(shù)、紅黑樹(shù)等。但是Hash表卻有O(C)線性級(jí)別的查找效率(不沖突情況下查找效率達(dá)到O(1))。大家好好體會(huì)一下:Hash表的思想和桶排序是不是有一曲同工之妙呢?

    基數(shù)排序

    上面的問(wèn)題是多關(guān)鍵字的排序,但單關(guān)鍵字也仍然可以使用這種方式。

    比如字符串“abcd” “aesc” “dwsc” “rews”就可以把每個(gè)字符看成一個(gè)關(guān)鍵字。另外還有整數(shù) 425、321、235、432也可以每個(gè)位上的數(shù)字為一個(gè)關(guān)鍵字。

    ?

    基數(shù)排序的思想就是將待排數(shù)據(jù)中的每組關(guān)鍵字依次進(jìn)行桶分配。比如下面的待排序列:

    278、109、063、930、589、184、505、269、008、083

    我們將每個(gè)數(shù)值的個(gè)位,十位,百位分成三個(gè)關(guān)鍵字: 278 -> k1(個(gè)位)=8 ,k2(十位)=7 ,k3=(百位)=2。

    然后從最低位個(gè)位開(kāi)始(從最次關(guān)鍵字開(kāi)始),對(duì)所有數(shù)據(jù)的k1關(guān)鍵字進(jìn)行桶分配(因?yàn)?#xff0c;每個(gè)數(shù)字都是 0-9的,因此桶大小為10),再依次輸出桶中的數(shù)據(jù)得到下面的序列。

    930、063、083、184、505、278、008、109、589、269

    再對(duì)上面的序列接著進(jìn)行針對(duì)k2的桶分配,輸出序列為:

    505、008、109、930、063、269、278、083、184、589

    最后針對(duì)k3的桶分配,輸出序列為:

    008、063、083、109、184、269、278、505、589、930

    ?

    性能分析

    很明顯,基數(shù)排序的性能比桶排序要略差。每一次關(guān)鍵字的桶分配都需要O(N)的時(shí)間復(fù)雜度,而且分配之后得到新的關(guān)鍵字序列又需要O(N)的時(shí)間復(fù)雜度。假如待排數(shù)據(jù)可以分為d個(gè)關(guān)鍵字,則基數(shù)排序的時(shí)間復(fù)雜度將是O(d*2N) ,當(dāng)然d要遠(yuǎn)遠(yuǎn)小于N,因此基本上還是線性級(jí)別的。基數(shù)排序的空間復(fù)雜度為O(N+M),其中M為桶的數(shù)量。一般來(lái)說(shuō)N>>M,因此額外空間需要大概N個(gè)左右。

    ?

    但是,對(duì)比桶排序,基數(shù)排序每次需要的桶的數(shù)量并不多。而且基數(shù)排序幾乎不需要任何“比較”操作,而桶排序在桶相對(duì)較少的情況下,桶內(nèi)多個(gè)數(shù)據(jù)必須進(jìn)行基于比較操作的排序。因此,在實(shí)際應(yīng)用中,基數(shù)排序的應(yīng)用范圍更加廣泛。

    轉(zhuǎn)載于:https://www.cnblogs.com/chuninggao/p/7281117.html

    總結(jié)

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

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