第一节 排序概论
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基本相同。
这里给出网上下载的基数排序的截图: