桶排序(Bucket sort)
桶排序思想:
桶排序的基本思想:
假設有一組長度為N的待排關鍵字序列K[1….n]。首先將這個序列劃分成M個的子區間(桶) 。然後基於某種對映函式 ,將待排序列的關鍵字k對映到第i個桶中(即桶陣列B的下標 i) ,那麼該關鍵字k就作為B[i]中的元素(每個桶B[i]都是一組大小為N/M的序列)。接著對每個桶B[i]中的所有元素進行比較排序(可以使用快排)。然後依次列舉輸出B[0]….B[M]中的全部內容即是一個有序序列。
假如待排序列K= {49、 38 、 35、 97 、 76、 73 、 27、 49 }。這些資料全部在1—100之間。因此我們定製10個桶,然後確定對映函式f(k)=k/10。則第一個關鍵字49將定位到第4個桶中(49/10=4)。依次將所有關鍵字全部堆入桶中,並在每個非空的桶中進行快速排序。
桶排序代價分析
桶排序利用函式的對映關係,減少了幾乎所有的比較工作。實際上,桶排序的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),如果輸入資料非常龐大,而桶的數量也非常多,則空間代價無疑是昂貴的。此外,桶排序是穩定的。
桶排序的的步驟:
申請一定數量的桶
按照一個設定好的對映函式,將序列裡面的元素對映到對應的桶裡。
遍歷一遍所有的桶,將各個桶內的元素進行排序,排序演算法可以採用氣泡排序,插入排序,快速排序,歸併排序等等適合的演算法
將所有桶內的元素按照順序組合起來就是我們需要的有序序列
分類:
第一種:桶號包含所有元素
例:
#include <stdio.h>
int main()
{
int book[1001],i,j,t,n;
for(i=0;i<=1000;i++)
book[i]=0;
scanf("%d",&n);//輸入一個數n,表示接下來有n個數
for(i=1;i<=n;i++)//迴圈讀入n個數,並進行桶排序
{
scanf("%d",&t); //把每一個數讀到變數t中
book[t]++; //進行計數,對編號為t的桶放一個小旗子
}
for(i=1000;i>=0;i--) //依次判斷編號1000~0的桶
for(j=1;j<=book[i];j++) //出現了幾次就將桶的編號列印幾次
printf("%d ",i);
getchar();
return 0;
}
第二種:待排元素大小和個數相差遠,桶號不宜和元素值對應
例:
假如待排序列K= {49、38 、35、 97 、 76、 73 、 27、 49 }。這些資料全部在1—100之間。因此我們定製10個桶,然後確定對映函式f(k)=k/10。則第一個關鍵字49將定位到第4個桶中(49/10=4)。依次將所有關鍵字全部堆入桶中,並在每個非空的桶中進行快速排序後得到如下圖所示:
此程式沒用上圖資料
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
int main(){
LNode *p,*node,*q;
int i,t;
int a[6]={4,11,10,24,3,22};
LinkList b[6];
for(i=0;i<6;i++){
b[i]=(LinkList)malloc(sizeof(LNode));
b[i]->data=0;
b[i]->next=NULL;
}
for(i=0;i<6;i++){
node=(LinkList)malloc(sizeof(LNode));
node->data=a[i];
node->next=NULL;
t=a[i]/10;
p=b[t];
if(p->next==NULL){
p->next=node;
}
else{
while(p->next!=NULL&&p->next->data<=node->data)
p=p->next;
node->next=p->next;
p->next=node;
}
}
for(i=0;i<6;i++){
for(q=b[i]->next;q!=NULL;q=q->next)
printf("%d ",q->data);
}
return 0;
}