為何我決定以后都用快速排序


排序,看似很簡單的問題,實則有大內容。我們人人都會玩撲克牌,而每次向牌堆摸牌插入手中時,無意間,我們已在排序。我們每摸出一張牌,都會按大小順序把它放入合適的位置,即將這次摸來的牌插入手中首次比其大的牌之前。因而每次放完牌,我們手中的牌總是有序的。這種方法甚是簡單,以至於我在這里說都怕被人笑話。但是,我們要慶幸的是幸好一副撲克牌只有54張,而不是5400,54000張。否則,你再這樣排序試試。

簡單的方法必然付出簡單的代價,那就是耗時太嚴重。為此,總有一些人不滿足簡單耗時的方法,他們努力找出更加優越的排序算法。於是,折半插入排序,歸並排序,堆排序,快速排序,應用而生。

這里,我主要來談談歸並排序和快速排序。

所謂歸並排序,就是將一個大序列的排序問題分解成為兩個子序列的排序問題,然后對子序列遞歸使用同樣的方式進行排序(直到每個子序列只有一個元素,自然有序了),在子序列排好序后,再將結果合並起來。

分解是很容易的,主要功夫就花在合並上了,也就是說歸並排序的主要時間是花在歸並上的。下面簡單圖示一個歸並排序的流程。

 

下面看一下快速排序。快速排序其實就是先將任一元素作為杠桿點(通常是首元素),然后以杠桿點位分界,遍歷待排元素,小的放左邊,大的放右邊。

再將左右各進行一次這樣的排序,遞歸下去,直到所有元素均有序。

圖示如下:

至於插入排序,歸並排序,快速排序之間的差別,文字是很難描述的。因此,我們用程序來直觀對比一下:

下面結果為隨機產生的n個整數,然后分別利用插入排序,歸並排序,快速排序對其排序進行時間(單位為秒)比較。運行結果:

時間為0並不代表不需要運行時間,只是時間很短,達不到一個時鍾周期,就被忽略了。

從結果我們可以看出,數據量較小的情況下,集中排序效果相當,差別不明顯。然而數據量達到數萬數十萬及以上,孰優孰劣便一目了然了。200000個數據排序是,插入排序簡直不能忍,接近1分鍾,不管你能不能接受,反正我是不能接受。

因此,我決定,以后只用快速排序。特別是數據量很大時,不要抱着插入排序不放了,其實冒泡排序亦然。所以,快速排序,名副其實的快,當然,歸並排序也是相當不錯的。

附上拙劣的源程序。不妥之處,望披露指正。xuyongjie1128@hotmail.com

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

#include<iostream.h>
#include<stdlib.h>
#include<time.h>

void Insert_sort(int a[],int n)//插入排序
{
    int i,j,key;
    for(j=1;j<n;j++)
    {
        key=a[j];
        i=j-1;
        while(i>=0&&a[i]>key)
        {
            a[i+1]=a[i];
            i--;
        }
        a[i+1]=key;
    }
}

int Partition(int a[],int m,int n)//快速排序分解
{
    int x,i,j,temp;
    x=a[m];
    i=m;
    for(j=m+1;j<=n;j++)
    {
        if(a[j]<=x)
        {
            i=i+1;
            temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
    }
    temp=a[i];
    a[i]=a[m];
    a[m]=temp;
    return i;
}

void QuickSort(int A[],int begin,int end)//快速排序
{
    int q;
    if(begin<end)
    {
        q=Partition(A,begin,end);
        QuickSort(A,begin,q-1);
        QuickSort(A,q+1,end);
    }
}


int *Union(int a[],int b[],int abegin,int aend,int bbegin,int bend)//歸並
{
    int i=abegin,j=bbegin;
    int *c=new int[aend-abegin+1+bend-bbegin+1];
    while(i<=aend&&j<=bend)
    {
        if(a[i]<b[j])
        {
            c[i-abegin+j-bbegin]=a[i];
            i++;
        }
        else
        {
            c[i-abegin+j-bbegin]=b[j];
            j++;
        }
    }
    if(i>aend)
    {
        while(j<=bend)
        {
            c[i-abegin+j-bbegin]=b[j];
            j++;
        }
    }
    else
    {
        while(i<=aend)
        {
            c[i-abegin+j-bbegin]=a[i];
            i++;
        }
    }
    return c;
}

int *UnionSort(int a[],int begin,int end)//歸並排序
{
    int q=(begin+end)/2;
    if(begin==end)
    {
        int *temp=&a[begin];
        return temp;
    }
    if(begin<end)
    {
        return Union(UnionSort(a,begin,q),UnionSort(a,q+1,end),0,q-begin,0,end-q-1);
    }
}

int *CreateRandomArry(int n)
{
    int *data=new int[n];
    int i;
    for(i=0;i<n;i++)
    {
        data[i]=rand();
    }
    return data;
}


void main()//主函數
{
    int i,n;
    time_t tstart,tend;
    while(true)
    {
        cout<<"\n輸入待排序數個數:\n";
        cin>>n;
        if(n==0)
        {
            break;
        }
        int *data=CreateRandomArry(n);
        int *data2=new int[n];
        for(i=0;i<n;i++)
        {
            data2[i]=data[i];
        }

        long now=clock();
        Insert_sort(data,n);
        cout<<"插入排序時間:"<<double(clock()-now)/CLOCKS_PER_SEC<<endl;

        now=clock();
        int *result=UnionSort(data2,0,n-1);
        cout<<"歸並排序時間:"<<double(clock()-now)/CLOCKS_PER_SEC<<endl;

        now=clock();
        QuickSort(data2,0,n-1);
        cout<<"快速排序時間:"<<double(clock()-now)/CLOCKS_PER_SEC<<endl;
    }
}

徐永傑

2013 年1月 18號

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM