1. 程式人生 > >桶排序(Bucket sort)

桶排序(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;
}