排序,看似很简单的问题,实则有大内容。我们人人都会玩扑克牌,而每次向牌堆摸牌插入手中时,无意间,我们已在排序。我们每摸出一张牌,都会按大小顺序把它放入合适的位置,即将这次摸来的牌插入手中首次比其大的牌之前。因而每次放完牌,我们手中的牌总是有序的。这种方法甚是简单,以至于我在这里说都怕被人笑话。但是,我们要庆幸的是幸好一副扑克牌只有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号