所有排序默认均为升序。
一、插入排序
1.1直接插入排序
/* 直接插入排序 */ #include<iostream> #include<stdio.h> using namespace std; void InsertSort(int R[],int n){//对R[0..n-1]按递增有序进行直接插入排序 int i,j; int tmp; for(i=1;i<n;++i){ tmp=R[i]; j=i-1;//从右向左在有序区R[0..i-1]中找R[i]的插入位置 while(j>=0&&tmp<R[j]){ R[j+1]=R[j];//将关键字大于R[i].key的元素后移 --j; } R[j+1]=tmp;//在j+1处插入R[i] } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; InsertSort(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
1.2折半插入排序
/* 折半插入排序 */ #include<iostream> #include<stdio.h> using namespace std; void InsertSort1(int R[],int n){//对R[0..n-1]按递增顺序进行折半插入排序 int i,j,low,high,mid; int tmp; for(i=1;i<n;++i){ tmp=R[i];//将R[i]保存到tmp中 low=0; high=i-1; while(low<=high){//在R[low..high]中折半查找有序插入的位置 mid=(low+high)/2;//取中间位置 if(tmp<R[mid])high=mid-1;//插入点在左半区 else low=mid+1;//插入点在右半区 } for(j=i-1;j>=high+1;--j)//元素右移 R[j+1]=R[j]; R[high+1]=tmp;//插入 } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; InsertSort1(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
1.3希尔排序
/* 希尔排序 */ #include<iostream> #include<stdio.h> using namespace std; void ShellSort(int R[],int n){//希尔排序算法 int i,j,gap; int tmp; gap=n/2;//增量置初值 while(gap>0){ for(i=gap;i<n;++i){//对所有相隔gap位置的元素组采用直接插入排序 tmp=R[i]; j=i-gap; while(j>=0&&tmp<R[j]){//对相隔gap位置的元素组进行排序 R[j+gap]=R[j]; j=j-gap; } R[j+gap]=tmp; } gap=gap/2;//减小增量 } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; ShellSort(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
二、交换排序
2.1冒泡排序
/* 冒泡排序 */ #include<iostream> #include<stdio.h> using namespace std; void BubbleSort(int R[],int n){ int i,j; int tmp; for(i=0;i<n-1;++i){ for(j=n-1;j>i;--j){//比较,找出本趟关键字最小的元素 if(R[j]<R[j-1]){ tmp=R[j];//R[j]与R[j-1]进行交换,将关键字最小的元素前移 R[j]=R[j-1]; R[j-1]=tmp; } } } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; BubbleSort(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
/* 改进的冒泡排序 */ #include<iostream> #include<stdio.h> using namespace std; void BubbleSort1(int R[],int n){ int i,j; bool exchange; int tmp; for(i=0;i<n-1;++i){ exchange=false; for(j=n-1;j>i;--j){//比较,找出关键字最小的元素 if(R[j]<R[j-1]){ tmp=R[j];//R[j]与R[j-1]进行交换,将关键字最小的元素前移 R[j]=R[j-1]; R[j-1]=tmp; exchange=true; } } if(!exchange)return;//本趟没有发生交换,中途结束算法 } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; BubbleSort1(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
2.2快速排序
/* 快速排序 */ #include<iostream> #include<stdio.h> using namespace std; void QuickSort(int R[],int s,int t){//对R[s]至R[t]的元素进行快速排序 int i=s,j=t; int tmp; if(s<t){//区间内至少存在两个元素的情况 tmp=R[s];//用区间的第1个元素作为基准 while(i!=j){//从区间两端交替向中间扫描,直至i=j为止 while(j>i&&R[j]>=tmp)--j;//从右向左扫描,找第1个小于tmp的R[j] R[i]=R[j];//找到这样的R[j],R[i]与R[j]交换 while(i<j&&R[i]<=tmp)++i;//从左向右扫描,找第1个大于tmp的R[i] R[j]=R[i];//找到这样的R[i],R[i]与R[j]交换 } R[i]=tmp; QuickSort(R,s,i-1);//对左区间递归排序 QuickSort(R,i+1,t);//对右区间递归排序 } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; QuickSort(a,0,9); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
三、选择排序
3.1直接选择排序
/* 直接选择排序 */ #include<iostream> #include<stdio.h> using namespace std; void SelectSort(int R[],int n){ int i,j,k; int tmp; for(i=0;i<n-1;++i){//做第i趟排序 k=i; for(j=i+1;j<n;++j){//在当前无序区R[i..n-1]中选最小的R[k] if(R[j]<R[k])k=j;//k记下目前找到的最小关键字所在的位置 } if(k!=i){//交换R[i]和R[k] tmp=R[i]; R[i]=R[k]; R[k]=tmp; } } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; SelectSort(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
3.2堆排序
/* 堆排序 */ #include<iostream> #include<stdio.h> using namespace std; void sift(int R[],int low,int high){ int i=low,j=2*i;//R[j]是R[i]的左孩子 int tmp=R[i]; while(j<=high){ if(j<high&&R[j]<R[j+1])++j;//若右孩子较大,把j指向右孩子 if(tmp<R[j]){ R[i]=R[j];//将R[j]调整到双亲节点位置上 i=j;//修改i和j值,以便继续向下筛选 j=2*i; } else break;//筛选结束 } R[i]=tmp;//被筛选节点的值放入最终位置 } void HeapSort(int R[],int n){ int i; int tmp; for(i=n/2;i>=1;--i)sift(R,i,n);//循环建立初始堆 for(i=n;i>=2;--i){//进行n-1趟堆排序,每一趟堆排序的元素个数减1 tmp=R[1];//将最后一个元素同当前区间内R[1]对换 R[1]=R[i]; R[i]=tmp; sift(R,1,i-1);//筛选R[1]节点,得到i-1个节点的堆 } } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; HeapSort(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
四、归并排序
/* 归并排序 */ #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; void Merge(int R[],int low,int mid,int high){ int *R1; int i=low,j=mid+1,k=0;//k是R1的下标,i、j分别为第1、2段的下标 R1=(int *)malloc((high-low+1)*sizeof(int));//动态分配空间 while(i<=mid&&j<=high){//在第1段和第2段均未扫描完时循环 if(R[i]<R[j]){//将第1段中的元素放入R1中 R1[k]=R[i]; ++i; ++k; } else{//将第2段中的元素放入R1中 R1[k]=R[j]; ++j; ++k; } } while(i<=mid){//将第1段余下部分复制到R1中 R1[k]=R[i]; ++i; ++k; } while(j<=high){//将第2段余下部分复制到R1中 R1[k]=R[j]; ++j; ++k; } for(k=0,i=low;i<=high;++k,++i)//将R1复制回R中 R[i]=R1[k]; free(R1); } void MergePass(int R[],int length,int n){//对整个表进行一趟归并 int i; for(i=0;i+2*length-1<n;i=i+2*length)//归并length长的两相邻子表 Merge(R,i,i+length-1,i+2*length-1); if(i+length-1<n)//余下两个子表,后者长度小于length Merge(R,i,i+length-1,n-1);//归并这两个子表 } void MergeSort(int R[],int n){//自底向上的二路归并算法 int length; for(length=1;length<n;length=2*length)//进行log2(n)趟归并 MergePass(R,length,n); } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; MergeSort(a,10); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
五、分配排序
5.1桶排序
5.2基数排序
性能:
排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | 复杂性 | ||
平均情况 | 最坏情况 | 最好情况 | ||||
1.1直接插入排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 | 简单 |
1.2折半插入排序 | ||||||
1.3希尔排序 | O(n^1.3) | O(1) | 不稳定 | 较复杂 | ||
2.1冒泡排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 | 简单 |
2.2快速排序 | O(nlog2(n) | O(n^2) | O(nlog2(n) | O(log2(n) | 不稳定 | 较复杂 |
3.1直接选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 | 简单 |
3.2堆排序 | O(nlog2(n) | O(nlog2(n) | O(nlog2(n) | O(1) | 不稳定 | 较复杂 |
4归并排序 | O(nlog2(n) | O(nlog2(n) | O(nlog2(n) | O(n) | 稳定 | 较复杂 |
5.1桶排序 | ||||||
5.2基数排序 | O(d(n+r)) | O(d(n+r)) | O(d(n+r)) | O(r) | 稳定 | 较复杂 |
然而使用过程中大都直接调用sort,qsort函数,如下:
一、sort
头文件:algorithm
①sort(首地址,首地址+排序个数);//默认升序
参数1:首地址
参数2:尾地址的下一地址
例:sort(a,b);//表示排序区间为[a,b)
简单来说,有一个数组int a[100],要对从a[0]到a[99]的元素进行排序,只要写sort(a,a+100);就行了。
②sort(首地址,首地址+排序个数,比较函数);//按比较函数进行排序
比较函数的返回值:The value returned indicates whether the element passed as first argument is considered to go before the second in the specific strict weak ordering it defines.
1.int
/* sort排序 int升序 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; sort(a,a+10);//默认升序 for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
/* sort排序 int降序 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; bool cmp(int a,int b){ return a>b;//降序 } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; sort(a,a+10,cmp);// for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
2.char
/* sort排序 char升序 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; int main(){ char a[]={'5','4','3','2','1','0','9','8','7','6'}; int i; sort(a,a+10);//默认升序 for(i=0;i<10;++i) printf("%c ",a[i]); printf(" "); return 0; }
/* sort排序 char降序 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; bool cmp(char a,char b){ return a>b;//降序 } int main(){ char a[]={'5','4','3','2','1','0','9','8','7','6'}; int i; sort(a,a+10,cmp);// for(i=0;i<10;++i) printf("%c ",a[i]); printf(" "); return 0; }
3.double
/* sort排序 double升序 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; int main(){ double a[]={5,4,3,2,1,0,9,8,7,6}; int i; sort(a,a+10);//默认升序 for(i=0;i<10;++i) printf("%.2f ",a[i]); printf(" "); return 0; }
/* sort排序 double降序 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; bool cmp(double a,double b){ return a>b;//降序(估计也有精度问题,需注意。) } int main(){ double a[]={5,4,3,2,1,0,9,8,7,6}; int i; sort(a,a+10,cmp);// for(i=0;i<10;++i) printf("%.2f ",a[i]); printf(" "); return 0; }
4.结构体
/* sort排序 结构体排序 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; struct node{ int a; int b; }a[10]; bool cmp(node a,node b){ if(a.a!=b.a)return a.a<b.a;//a升 return a.b>b.b;//b降 } int main(){ a[0].a=a[1].a=a[2].a=5; a[0].b=3;a[1].b=2;a[2].b=1; a[3].a=a[4].a=a[5].a=0; a[3].b=9;a[4].b=8;a[5].b=7; int i; sort(a,a+6,cmp);// for(i=0;i<6;++i) printf("%d %d ",a[i].a,a[i].b); return 0; }
5.字符串
错误代码1:
/* sort排序 字符串升序,错误 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; int main(){ char a[4][20]={"cccc","bbbb","bbcccc","aaaaaaa"}; int i; sort(a,a+4);//默认升序 for(i=0;i<4;++i) printf("%s ",a[i]); return 0; }
错误代码2:
/* sort排序 字符串升序,错误 */ #include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; bool cmp(char a[],char b[]){ return strcmp(a,b)<0;//升序 } int main(){ char a[4][20]={"cccc","bbbb","bbcccc","aaaaaaa"}; int i; sort(a,a+4,cmp);// for(i=0;i<4;++i) printf("%s ",a[i]); return 0; }
正确代码:字符串写到结构体中。
/* sort排序 字符串升序 */ #include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; struct node{ char a[20]; }a[4]; bool cmp(node a,node b){ return strcmp(a.a,b.a)<0;//升序 } int main(){ strcpy(a[0].a,"cccc"); strcpy(a[1].a,"bbbb"); strcpy(a[2].a,"bbcccc"); strcpy(a[3].a,"aaaaaaa"); int i; sort(a,a+4,cmp);// for(i=0;i<4;++i) printf("%s ",a[i].a); return 0; }
由于cmp是针对于自定义类型node的,所以也可以通过运算符重载来实现排序的方式。
/* sort排序 字符串升序 */ #include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; struct node{ char a[20]; }a[4]; bool operator<(node a,node b){ return strcmp(a.a,b.a)<0;//(即a.a<b.a)升序 } int main(){ strcpy(a[0].a,"cccc"); strcpy(a[1].a,"bbbb"); strcpy(a[2].a,"bbcccc"); strcpy(a[3].a,"aaaaaaa"); int i; sort(a,a+4);// for(i=0;i<4;++i) printf("%s ",a[i].a); return 0; }
/* sort排序 字符串降序 */ #include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; struct node{ char a[20]; }a[4]; bool operator<(node a,node b){ return strcmp(a.a,b.a)>0;//(即a.a>b.a)降序 } int main(){ strcpy(a[0].a,"cccc"); strcpy(a[1].a,"bbbb"); strcpy(a[2].a,"bbcccc"); strcpy(a[3].a,"aaaaaaa"); int i; sort(a,a+4);// for(i=0;i<4;++i) printf("%s ",a[i].a); return 0; }
二、qsort
头文件:stdlib.h
qsort(首地址,排序个数,每个元素占用空间大小,比较函数);
设比较函数:int compar (const void* p1, const void* p2);
比较函数的返回值:
return value | meaning |
---|---|
<0 |
The element pointed to by p1 goes before the element pointed to by p2 |
0 |
The element pointed to by p1 is equivalent to the element pointed to by p2 |
>0 |
The element pointed to by p1 goes after the element pointed to by p2 |
For types that can be compared using regular relational operators, a general compar function may look like:
int compareMyType (const void * a, const void * b) { if ( *(MyType*)a < *(MyType*)b ) return -1; if ( *(MyType*)a == *(MyType*)b ) return 0; if ( *(MyType*)a > *(MyType*)b ) return 1; }
1.int
/* qsort排序 int升序 */ #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; int cmp(const void *a,const void *b){ return *(int *)a-*(int *)b;//升序 } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; qsort(a,10,sizeof(int),cmp); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
/* qsort排序 int升序 */ #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; int cmp(const void *a,const void *b){ //return *(int *)a-*(int *)b;//升序 //与下面等价 int *A=(int *)a;//强制转化 int *B=(int *)b; return *A-*B; } int main(){ int a[]={5,4,3,2,1,0,9,8,7,6},i; qsort(a,10,sizeof(int),cmp); for(i=0;i<10;++i) printf("%d ",a[i]); printf(" "); return 0; }
2.char
/* qsort排序 char升序 */ #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; int cmp(const void *a,const void *b){ return *(char *)a-*(char *)b;//升序 } int main(){ char a[]={'5','4','3','2','1','0','9','8','7','6'}; int i; qsort(a,10,sizeof(char),cmp); for(i=0;i<10;++i) printf("%c ",a[i]); printf(" "); return 0; }
3.double
/* qsort排序 double升序 */ #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; int cmp(const void *a,const void *b){ return *(double *)a<*(double *)b?-1:1;//升序 } int main(){ double a[]={5,4,3,2,1,0,9,8,7,6}; int i; qsort(a,10,sizeof(double),cmp); for(i=0;i<10;++i) printf("%.2f ",a[i]); printf(" "); return 0; }
4.结构体
/* qsort排序 结构体排序 */ #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; struct node{ int a; int b; }a[10]; int cmp(const void *a,const void *b){ node *A=(node *)a; node *B=(node *)b; if(A->a!=B->a)return A->a-B->a;//a升 return B->b-A->b;//b降 } int main(){ a[0].a=a[1].a=a[2].a=5; a[0].b=3;a[1].b=2;a[2].b=1; a[3].a=a[4].a=a[5].a=0; a[3].b=9;a[4].b=8;a[5].b=7; int i; qsort(a,6,sizeof(node),cmp); for(i=0;i<6;++i) printf("%d %d ",a[i].a,a[i].b); return 0; }
5.字符串
/* qsort排序 字符串升序 */ #include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> using namespace std; int cmp(const void *a,const void *b){ return strcmp((char *)a,(char *)b);//升序 } int main(){ char a[4][20]={"cccc","bbbb","bbcccc","aaaaaaa"}; int i; qsort(a,4,sizeof(a[0]),cmp); for(i=0;i<4;++i) printf("%s ",a[i]); return 0; }