排序精讲
第一节 排序概论
1.1 排序定义
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序。若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。内部排序的过程是一个逐步扩大记录的有序序列长度的过程。
1.2 排序分类
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。
1.3 排序算法
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。首先比较a[1]与a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变。再比较a[2]与a[3]的值,若a[2]大于a[3]则交换两者的值,否则不变。再比较a[3]与a[4],以此类推,最后比较a[n-1]与a[n]的值。这样处理一轮后,a[n]的值一定是这组数据中最大的。再对a[1]~a[n-1]以相同方法处理一轮,则a[n-1]的值一定是a[1]~a[n-1]中最大的。再对a[1]~a[n-2]以相同方法处理一轮,以此类推。共处理n-1轮后a[1]、a[2]、……a[n]就以升序排列了。降序排列与升序排列相类似,若a[1]小于a[2]则交换两者的值,否则不变,后面以此类推。 总的来讲,每一轮排序后最大(或最小)的数将移动到数据序列的最后,理论上总共要进行n(n-1)/2次交换。实际,当一次排序过后没有发生交换,那么就算作排序成功,即可退出程序。
/*冒泡排序(改进后)*/ void BubbleSort(int a[],int n) { while(n>0) { int k; k=n-1; n=0; for(int i=1;i<=k;i++) if(a[i]>a[i+1]) { swap(a[i+1],a[i]); n=i; } } }
【1.3.2 选择排序】
/*选择排序*/ void SelectSort(int a[],int n) { for(int i=1;i<n;i++) { int k;k=i; for(int j=i+1;j<=n;j++) if(a[j]<a[k]) k=j; if(k!=i) swap(a[i],a[k]); } }
【1.3.3 插入排序】
插入排序:已知一组升序排列数据a[1]、a[2]、……a[n],一组无序数据b[1]、b[2]、……b[m],需将二者合并成一个升序数列。首先比较b[1]与a[1]的值,若b[1]大于a[1],则跳过,比较b[1]与a[2]的值,若b[1]仍然大于a[2],则继续跳过,直到b[1]小于a数组中某一数据a[x],则将a[x]~a[n]分别向后移动一位,将b[1]插入到原来a[x]的位置这就完成了b[1]的插入。b[2]~b[m]用相同方法插入。(若无数组a,可将b[1]当作n=1的数组a)
/*插入排序*/ void InsertSort(int a[],int n) { for(int i=2;i<=n;i++) { int tmp,j; tmp=a[i];j=i-1; while(a[j]>tmp) {a[j+1]=a[j];j--;} a[j+1]=tmp; } }
【1.3.4 希尔排序】
由希尔在1959年提出。已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。发现当n不大时,插入排序的效果很好。首先取一增量d(d<n),将a[1]、a[1+d]、a[1+2d]……列为第一组,a[2]、a[2+d]、a[2+2d]……列为第二组,a[d]、a[2d]、a[3d]……列为最后一组以次类推,在各组内用插入排序,然后取d'<d,重复上述操作,直到d=1。
/*希尔排序*/ void ShellSort(int a[],int n) { for(int i=n/2;i>0;i/=2) for(int j=i+1;j<=n;j++) { int key=a[j],k; for(k=j-i;k>=0&&a[k]>key;k-=i) a[k+i]=a[k]; a[k+i]=key; } }
【1.3.5 快速排序】
快速排序是目前已知的常用排序算法中最快的排序方法。已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。首先任取数据a[x]作为基准。比较a[x]与其它数据并排序,使a[x]排在数据的第k位,并且使a[1]~a[k-1]中的每一个数据<a[x],a[k+1]~a[n]中的每一个数据>a[x],然后采用分治的策略分别对a[1]~a[k-1]和a[k+1]~a[n]两组数据进行快速排序。
/*快速排序*/ void QuickSort(int a[],int l,int r) { int i,j,mid; i=l;j=r; mid=a[(l+r)/2]; while(i<=j) { while(a[i]<mid) i++; while(a[j]>mid) j--; if(i<=j) { swap(a[i],a[j]); i++;j--; } } if(l>j) QuickSort(a,l,j); if(i<r) QuickSort(a,i,r); }
快速排序在C++中也有现成的,要用到STL模板。
#include <stdlib.h> /*这是升序*/ int cmpup(const void *x,const void *y) { return *(int*) x - *(int*) y; } /**********************************/ /*这是降序*/ int cmpdown(const void *x,const void *y) { return *(int*) y - *(int*) x; } /**********************************/ void Qsort(int a[],int n) { qsort(a,n,sizeof(int),cmpup); //如果是降序,那么就是: qsort(a,n,sizeof(int),cmpdown); }
【1.3.6 桶排序】
已知一组无序正整数数据a[1]、a[2]、……a[n],需将其按升序排列。首先定义一个数组x[m],且m>=a[1]、a[2]、……a[n],接着循环n次,每次x[a]++.
#include <iostream> using namespace std; int b[101],k,n; int main() { cin>>n; for(int i=0;i<=100;i++) b[i]=0; for(int i=1;i<=n;i++) { cin>>k; b[k]=b[k]+1; } for(int i=0;i<=100;i++) while(b[i]>0) { cout<<i<<' '; b[i]--; } return 0; }
【1.3.7 归并排序】
#include <iostream> using namespace std; int n,m,s[101],r[101],a[101]; int MergeSort() { int i=0,j=0,k=0; while ((i<n)&&(j<m)) { if (s[i]<=r[j]) {a[k]=s[i];i++;k++;} else {a[k]=r[j];j++;k++;} while (i<n) {a[k]=s[i];i++;k++;} while (j<m) {a[k]=r[j];j++;k++;} } } int main() { cin>>n; for(int x=0;x<n;x++) cin>>s[x]; cin>>m; for(int x=0;x<m;x++) cin>>r[x]; MergeSort(); for(int x=0;x<n+m;x++) cout<<a[x]<<' '; cout<<endl; return 0; }
【1.3.8 堆排序】
堆排序的要素就是让所有的左子树都比根及右子树大,但不太稳定。
#include <iostream> using namespace std; int a[1000001],n; void EditHeap(int i,int s) { int j; if (2*i<=s) { a[0]=a[i];j=i; if (a[2*i]>a[0]) {a[0]=a[2*i];j=2*i;} if ((2*i+1<=s)&&(a[2*i+1]>a[0])) {a[0]=a[2*i+1];j=2*i+1;} if (j!=i) {a[j]=a[i];a[i]=a[0];EditHeap(j,s);} } } void BuildHeap() { int i,j; for (i=n/2;i>=1;i--) { a[0]=a[i];j=i; if (a[2*i]>a[0]) {a[0]=a[2*i];j=2*i;} if ((2*i+1<=n)&&(a[2*i+1]>a[0])) {a[0]=a[2*i+1];j=2*i+1;} if (j!=i) {a[j]=a[i];a[i]=a[0];EditHeap(j,n);} } } void HeapSort() { BuildHeap(); for(int i=n;i>=2;i--) { a[0]=a[i]; a[i]=a[1]; a[1]=a[0]; EditHeap(1,i-1); } } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; HeapSort(); for(int i=1;i<=n;i++) cout<<a[i]<<' '; cout<<endl; return 0; }
【1.3.9 sort排序】
sort排序是指使用C++STL算法库中的sort函数进行任意类型数据排序。
#include <algorithm> int sortsort(int a[],int n) { sort(a,a+n); }
【1.3.10 基数排序】
基数排序(radix sort)则是属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。也称“桶排序”,与1.3.6基本相同。
这里给出网上下载的基数排序的截图: