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