排序結構6 桶排序

2021-07-04 03:37:16 字數 2959 閱讀 8691

從《基於比較的排序結構總結 》中我們知道:全依賴「比較」操作的排序演算法時間複雜度的乙個下界o(n*logn)。但確實存在更快的演算法。這些演算法並不是不用「比較」操作,也不是想辦法將比較操作的次數減少到 logn。而是利用對待排資料的某些限定性假設 ,來避免絕大多數的「比較」操作。桶排序就是這樣的原理。

桶排序的基本思想

假設有一組長度為n的待排關鍵字序列k[1....n]。首先將這個序列劃分成m個的子區間(桶) 。然後基於某種對映函式 ,將待排序列的關鍵字k對映到第i個桶中(即桶陣列b的下標 i) ,那麼該關鍵字k就作為b[i]中的元素(每個桶b[i]都是一組大小為n/m的序列)。接著對每個桶b[i]中的所有元素進行比較排序(可以使用快排)。然後依次列舉輸出b[0]....b[m]中的全部內容即是乙個有序序列。

[桶—關鍵字]對映函式

bindex=f(key)   其中,bindex 為桶陣列b的下標(即第bindex個桶), k為待排序列的關鍵字。桶排序之所以能夠高效,其關鍵在於這個對映函式,它必須做到:如果關鍵字k1很顯然,對映函式的確定與資料本身的特點有很大的關係,我們下面舉個例子:

假如待排序列k= 。這些資料全部在1—100之間。因此我們定製10個桶,然後確定對映函式f(k)=k/10。則第乙個關鍵字49將定位到第4個桶中(49/10=4)。依次將所有關鍵字全部堆入桶中,並在每個非空的桶中進行快速排序後得到如下圖所示:

對上圖只要順序輸出每個b[i]中的資料就可以得到有序序列了。

桶排序代價分析

桶排序利用函式的對映關係,減少了幾乎所有的比較工作。實際上,桶排序的f(k)值的計算,其作用就相當於快排中劃分,已經把大量資料分割成了基本有序的資料塊(桶)。然後只需要對桶中的少量資料做先進的比較排序即可。

對n個關鍵字進行桶排序的時間複雜度分為兩個部分:

(1) 迴圈計算每個關鍵字的桶對映函式,這個時間複雜度是o(n)。

(2) 利用先進的比較排序演算法對每個桶內的所有資料進行排序,其時間複雜度為  ∑ o(ni*logni) 。其中ni 為第i個桶的資料量。

很顯然,第(2)部分是桶排序效能好壞的決定因素。儘量減少桶內資料的數量是提高效率的唯一辦法(因為基於比較排序的最好平均時間複雜度只能達到o(n*logn)了)。因此,我們需要盡量做到下面兩點:

(1) 對映函式f(k)能夠將n個資料平均的分配到m個桶中,這樣每個桶就有[n/m]個資料量。

(2) 盡量的增大桶的數量。極限情況下每個桶只能得到乙個資料,這樣就完全避開了桶內資料的「比較」排序操作。當然,做到這一點很不容易,資料量巨大的情況下,f(k)函式會使得桶集合的數量巨大,空間浪費嚴重。這就是乙個時間代價和空間代價的權衡問題了。

對於n個待排資料,m個桶,平均每個桶[n/m]個資料的桶排序平均時間複雜度為:

o(n)+o(m*(n/m)*log(n/m))=o(n+n*(logn-logm))=o(n+n*logn-n*logm)

當n=m時,即極限情況下每個桶只有乙個資料時。桶排序的最好效率能夠達到o(n)。

總結:桶排序的平均時間複雜度為線性的o(n+c),其中c=n*(logn-logm)。如果相對於同樣的n,桶數量m越大,其效率越高,最好的時間複雜度達到o(n)。

當然桶排序的空間複雜度

為o(n+m),如果輸入資料非常龐大,而桶的數量也非常多,則空間代價無疑是昂貴的。此外,桶排序是穩定的。

桶排序在海量資料中的應用

一年的全國高考考生人數為500 萬,分數使用標準分,最低100 ,最高900 ,沒有小數,你把這500 萬元素的陣列排個序。

分析:對500w資料排序,如果基於比較的先進排序,平均比較次數為o(5000000*log5000000)≈1.112億。但是我們發現,這些資料都有特殊的條件:  100=

方法:建立801(900-100)個桶。將每個考生的分數丟進f(score)=score-100的桶中。這個過程從頭到尾遍歷一遍資料只需要500w次。然後根據桶號大小依次將桶中數值輸出,即可以得到乙個有序的序列。而且可以很容易的得到100分有***人,501分有***人。

實際上,桶排序對資料的條件有特殊要求,如果上面的分數不是從100-900,而是從0-2億,那麼分配2億個桶顯然是不可能的。所以桶排序有其侷限性,適合元素值集合並不大的情況。

源**

cpp**  

#include

#include

typedef

struct nodekeynode;  

void inc_sort(int keys,int size,int bucket_size)  

for(int j=0;jkeynode *node=(keynode *)malloc(sizeof(keynode));  

node->key=keys[j];  

node->next=null;  

//對映函式計算桶號

int index=keys[j]/10;  

//初始化p成為桶中資料鏈表的頭指標

keynode *p=bucket_table[index];  

//該桶中還沒有資料

if(p->key==0)else  

}  //列印結果

for(int b=0;bfor(keynode *k=bucket_table[b]->next; k!=null; k=k->next)  

cout

cout

void main();     

int size=sizeof(raw)/sizeof(int);     

inc_sort(raw,size,10);  

}  

上面源**的桶內資料排序,我們使用了基於單鏈表的直接插入排序演算法。可以使用基於雙向鍊錶的快排演算法提高效率。

演算法(6)桶排序 錯誤

bucket sort 現在假設我有一堆蛋,包括麻雀蛋 雞蛋 恐龍蛋,現在我要將這幾種蛋排序下序 有點常識就知道,這三種類別的蛋大小是不一樣的,而且每一類蛋的大小也是有區別的,現在我對這三種蛋進行排序,我是這樣排的 準備三個桶,把同一類別的蛋放到同乙個桶中,然後對每乙個桶內的蛋進行排序,然後按順序從...

排序 桶排序

首先,桶排序是一種簡單並且執行快的一種排序。第一步,對五個數進行排序。程式如下 include using namespace std int main 首先對陣列進行歸零 for int j 1 j 5 j 將輸入的數的個數存入陣列中。for int k 1 k 10 k 執行原理 桶排序,就是先...

排序演算法 桶排序

桶排序 bucket sort 或所謂的箱排序,是乙個排序演算法,工作的原理是將陣列分到有限數量的桶子裡。每個桶子再個別排序 有可能再使用別的排序演算法或是以遞迴方式繼續使用桶排序進行排序 桶排序是鴿巢排序的一種歸納結果。當要被排序的陣列內的數值是均勻分配的時候,桶排序使用線性時間 n 但桶排序並不...