演算法導論_第八章_線性時間排序

chudongfang2015發表於2016-06-29

演算法導論_第八章_線性時間排序


排序演算法的下界


決策樹模型


決策樹是一顆完全二叉樹


決策樹的每個節點代表需要比較的兩個數,葉節點為一個數的排序。所以任何正確的排

序,n個元


素的n!個排列情況都應該出現在葉節點上。

比較排序的最壞情況出現在比較次數為決策樹的高度,而決策數的高度

h<=lg(n!)=Ω(n*lg(n))


堆排序和歸併排序都是漸進最優的比較排序演算法


其執行時間上界為O(n*lg(n))




計數排序:


基本思想

對於每一個輸入的元素x,確定小於x的元素個數。利用這一資訊可以直接把x放到它在輸出

陣列中的位置上。


下面來看程式碼

/*************************************************************************
	> File Name: counting_sort.cpp
	> Author:chudongfang 
	> Mail:1149669942@qq.com 
	> Created Time: 2016年06月29日 星期三 08時42分35秒
 ************************************************************************/

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

void counting_sort(int a[],int b[],int n,int k);
int main(int argc,char *argv[])
{
    int a[100],b[100];
    int n;
    int max=-INF;
    printf("please input the number of array:");
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(max<a[i])  max=a[i];//確定輸入元素的最大值,便於開闢c陣列
    }
    
    counting_sort(a,b,n,max);
    for(int i=1;i<=n;i++)
        printf("%d ",b[i]);
    return 0;
}
//a陣列表示要排序的陣列,
//b表示排序過後的陣列,
//c表示a陣列元素在b陣列中的位置。
void counting_sort(int a[],int b[],int n,int k)
{
    int c[1000];
    
    for(int i=0;i<=k;i++)
        c[i]=0;
    
    for(int i=1;i<=n;i++)
        c[a[i]]++;//初始化為1代表有1個元素與其相等,為其本身
   
    /*******important**************/
    for(int i=1;i<=k;i++)//確定比其小或等於的元素的個數
        c[i]+=c[i-1];
    
    for(int j=n;j>=1;j--)
    {
        b[c[a[j]]]=a[j];//確定位置
        c[a[j]]--;//若有重複,則位置減1   
                  //在這裡,其保證瞭如果多個元素相同,其在b陣列中的順序與其
                  //在a陣列中的順序相同,就保證了其穩定性。  
    }
    /*****************************/
}




據計算其時間複雜度為Θ(n)

計數排序不涉及到比較,所以其脫離比較模型,時間複雜度可以降低很多,再者其具有

穩定性,對於附帶衛星資料來說,比較重要。

不過當k非常大時,可能導致記憶體空間利用過多。



基數排序:


排序思想

假定要對一個有10位的十進位制的數排序,那麼就從最低有效位開始進行排序,就是先對個位數進行排序,

然後十位,百位……直到排序完成,在排序過程中衛星資料順序不變,所以需要穩定的排序演算法。


這裡可以採用基數排序

下面上具體程式碼:

/*************************************************************************
	> File Name: radix_sort.cpp
	> Author:chudongfang 
	> Mail:1149669942@qq.com 
	> Created Time: 2016年06月29日 星期三 09時46分44秒
 ************************************************************************/

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef struct node
{
    int ge;
    int shi;
    int bai;
}NODE;
void counting_sort_ge(NODE a[],NODE b[],int n,int k);
void counting_sort_shi(NODE a[],NODE b[],int n,int k);
void counting_sort_bai(NODE a[],NODE b[],int n,int k);

int main(int argc,char *argv[])
{
    NODE a[100];
    NODE b[100];
    a[1].ge=1;
    a[1].shi=2;
    a[1].bai=3;
    
    a[2].ge=2;
    a[2].shi=2;
    a[2].bai=2;

    a[3].ge=7;
    a[3].shi=2;
    a[3].bai=3;
    
    a[4].ge=3;
    a[4].shi=1;
    a[4].bai=2;
    
    a[5].ge=5;
    a[5].shi=2;
    a[5].bai=3;
    int n=5,d=3;
    int max_ge=7;
    int max_shi=2;
    int max_bai=3;
    counting_sort_ge(a,b,n,max_ge);
    counting_sort_shi(b,a,n,max_shi);
    counting_sort_bai(a,b,n,max_bai);
    for (int i = 1; i <=5; ++i)
    {
        printf("%d%d%d\n",b[i].bai,b[i].shi,b[i].ge);
    }
            
    
    
    return 0;
}

void counting_sort_ge(NODE a[],NODE b[],int n,int k)
{
    int c[1000];
    
    for(int i=0;i<=k;i++)
        c[i]=0;
    
    for(int i=1;i<=n;i++)
        c[a[i].ge]++;//初始化為1代表有1個元素與其相等,為其本身
   
    /*******important**************/
    for(int i=1;i<=k;i++)//確定比其小或等於的元素的個數
        c[i]+=c[i-1];
    for(int j=n;j>=1;j--)
    {
        b[c[a[j].ge]]=a[j];//確定位置
        c[a[j].ge]--;//若有重複,則位置減1   
                  //在這裡,其保證瞭如果多個元素相同,其在b陣列中的順序與其
                  //在a陣列中的順序相同,就保證了其穩定性。  
    }
    /*****************************/
}
void counting_sort_shi(NODE a[],NODE b[],int n,int k)
{
    int c[1000];
    
    for(int i=0;i<=k;i++)
        c[i]=0;
    
    for(int i=1;i<=n;i++)
        c[a[i].shi]++;//初始化為1代表有1個元素與其相等,為其本身
   
    /*******important**************/
    for(int i=1;i<=k;i++)//確定比其小或等於的元素的個數
        c[i]+=c[i-1];
    
    for(int j=n;j>=1;j--)
    {
        b[c[a[j].shi]]=a[j];//確定位置
        c[a[j].shi]--;//若有重複,則位置減1   
                  //在這裡,其保證瞭如果多個元素相同,其在b陣列中的順序與其
                  //在a陣列中的順序相同,就保證了其穩定性。  
    }
    /*****************************/
}


void counting_sort_bai(NODE a[],NODE b[],int n,int k)
{
    int c[1000];
    
    for(int i=0;i<=k;i++)
        c[i]=0;
    
    for(int i=1;i<=n;i++)
        c[a[i].bai]++;//初始化為1代表有1個元素與其相等,為其本身
   
    /*******important**************/
    for(int i=1;i<=k;i++)//確定比其小或等於的元素的個數
        c[i]+=c[i-1];
    
    for(int j=n;j>=1;j--)
    {
        b[c[a[j].bai]]=a[j];//確定位置
        c[a[j].bai]--;//若有重複,則位置減1   
                  //在這裡,其保證瞭如果多個元素相同,其在b陣列中的順序與其
                  //在a陣列中的順序相同,就保證了其穩定性。  
    }
    /*****************************/
}









其利用了計數排序,對nd位數來說

其時間複雜度為:Θ(d*(n+k))

d為常數時且k=O(n),基數排序具有線性的時間代價

由於其不是原址排序,所以其會耗費大量記憶體空間,當記憶體非常珍貴的情況下,利用快排




桶排序


桶排序假設輸入的資料服從均勻分佈,平均情況下,其時間代價為O(n)


桶排序將[0,1)區間劃分為n個相同大小的子區間上,或稱為桶,然後將n個輸入數分別放到各個桶中,先對

桶中的數進行排序,然後遍歷每個桶,按照次序把各個桶中的元素列出來。


下面看具體程式碼

/*************************************************************************
	> File Name: bucket_sort.cpp
	> Author:chudongfang 
	> Mail:1149669942@qq.com 
	> Created Time: 2016年06月29日 星期三 10時50分26秒
 ************************************************************************/

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
void bucket_sort(float a[],float b[][100],int num[],int n,float max);
int main(int argc,char *argv[])
{
    float a[100];//要排序的陣列
    float b[100][100];//桶
    int num[100];//桶內的元素
    int n;
    float max=-INF;
    memset(num,0,sizeof(num));//賦值清零
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%f",&a[i]);
        if(a[i]>max)  max=a[i];//找到最大值
    }
    
    bucket_sort(a,b,num,n,max);//桶排序
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=num[i];j++)
            printf("%g ",b[i][j]);
    }
    return 0;
}


void bucket_sort(float a[],float b[][100],int num[],int n,float max)
{
    int i,j,k;
    for(i=1;i<=n;i++)
    {
        j=(int)(a[i]/max*n);//找到其應該放入桶的下標
        if(!j)  j++;  //如果為0,則變為1
        num[j]++;     //計數器加1
        
        /*************插入排序_部分功能********************/
        for(k=num[j];k>1&&b[j][k-1]>a[i];k--)
            b[j][k]=b[j][k-1];
        b[j][k]=a[i];
    }
}



桶排序效率分析:


桶排序的時間代價為

T(n)=Θ(n)+sum(O(n[i]^2))


最後求得其時間複雜度為:Θ(n)


即使輸入資料不服從平均分佈桶排序也仍然可以線上性時間內完成。只要輸入資料滿足所有桶的大小的平

方和與總的元素呈線性關係。







相關文章