分享八大排序算法,纯属自己的理解,如有错,请纠正,
只是以代码加上自己的少量注解分析八大排序算法而已,仅此而已,每种算法以相对数组下标从大到小排列的,输出是以数组下标大到小输出的,当然有很多不全面,有兴趣的自己深究。勿喷。
程序代码:
#include <stdio.h> //你懂的 #include <time.h> //使用计时代码 #include <stdlib.h> //使用产生随机代码 ////////直接插入排序属于稳定的排序,最坏时间复杂性为Θ(n^2),空间复杂度为O(1)。 int insertsort(int a[],int n){ int i,j; int b=0; //交换次数 for(i=0;i<n;i++){ // i 从 0 到 n-1 j=i+1; //j为i+1,即右边这个数据 //从大到小排序 if (a[j]>a[i]) //如果右边更大,改变顺序 { int t=a[j]; //中间值t //从右向左搜寻已排好的序列,如两数据逆序,则把此数据后退,数据t则待插入,直到正序就插入 while(i>=0&&t>a[i]) //特别注意此处是t,别写a[j],因为a[j]值会变的,通过i移动了,仔细分析便可知 { a[i+1]=a[i]; i--; b++; } a[i+1]=t;//i已达最小或已经正序,插入t值 b++; } i=j-1;//返回刚开始i的位置,不能忘记 } return b; } /////////////希尔排序又称缩小增量排序,是一种分组插入方法,比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素 int shellsort(int a[],int n){ int b=0,m=n; while(m>1) { m/=2; //取得增量,便于分组比较 { int i,j; //从0+增量m处选取依次递增,分组比较 for (i=m;i<n;i++) { int t=a[i]; j=i-m; //取得相隔m的数据比较 if (t>a[j]) { //和直接插入排序一样,从右向左如两数据逆序则数据后推,正序则插入 while(j>=0&&a[j]<t) { a[j+m]=a[j]; j-=m; //依次取得相同距离的数据,即分组排列 b++; } a[j+m]=t; //插入数据 b++; } } } } return b; } ////////////////冒泡排序 int bubblesort(int a[],int n){ int b=0; int i,j; for (i=n;i>0;i--)// i 从最右开始向左 { int is=1; for (j=0;j<i;j++)// j 从左向右走 //如果左数小于相邻的右数就交换,即将小数向后推,即冒泡,左数下标递增 if(a[j]<a[j+1]) { int t=a[j]; a[j]=a[j+1]; a[j+1]=t; is=0; b++; } b++; if(is) break; } return b; } /////////////////////快速排序,属于冒泡排序,排序过程可以递归进行 int quicksort(int a[],int left,int right){ static int bq; int i=left,j=right; int t=a[i]; //取得最左数据,一般数t取值最好是所有数据的大小的中值,即中位数,以使得分成差不多的两部分数 while(i<j){ //从最右数开始,依次左推,直到比较的两个数据为逆序时,将i处数据置另一数据 while((a[j]<t)&&(i<j)){ bq++; j--; } if(j>i){ a[i]=a[j]; i++; bq++; } //从上一部的a[i](非i++位置) 右边这个数开始,依次右推,直到比较的两个数据为逆序时,将j处数据置另一数据 while((a[i]>=t)&&(i<j)){ //注意i只增加到j-1 bq++; i++; } if(i<j){ a[j]=a[i]; j--; bq++; } } a[i]=t;//i处数据为t,则已分好两部分,i之前的数都大于t,j之后的小于t if(left<i-1) quicksort(a,left,i-1); if(right>i+1) quicksort(a,i+1,right); return bq; } //////////////////直接选择排序 int selectsort(int a[],int n){ int t,b=0; int i,j,k; for (i=0;i<n;i++)// i从 0 到 n-1 { k=i; //k初始为i的位置 for (j=i+1;j<n;j++){ // j从 i+1 到 n-1 if(a[j]>a[k]) k=j; //选择最大的数并用k保存位置,即保存下标 b++; } //k不是i的位置就交换数据 if(k!=i){ t=a[i]; a[i]=a[k]; a[k]=t; } b++; } return b; } ///////////////////堆排序。利用堆积树(堆)排序,大根堆和小根堆,将R[l..n]看成是一棵完全二叉树的顺序存储结构 //不稳定的排序方法。最坏时间复杂度为O(nlogn)。堆序的平均性能较接近于最坏性能。辅助空间为O(1) //理解此算法之前请先了解二叉树顺序存储结构表示或先画出二叉树 void heapadjust(int a[],int i,int n,int *bh){ int child; int t; for (t=a[i];2*i+1<n;i=child)//保证i节点有右儿子,t为父亲数据 { (*bh)++; child=2*i+1;//右儿子节点 //使父亲,左儿子,右儿子大小依次排序,未排好是会循环的 if(child<n-1&&a[child+1]<a[child]) child++; if(t>a[child]) a[i]=a[child]; else break; a[child]=t; } } int heapsort(int a[],int n){ int i; int bh=0; //由于是以0开始的顺序结构节点,所以才使得n/2-1结点即i都是倒数第二层(有时在倒数第三层),且i都有右儿子 for(i=n/2-1;i>=0;i--) heapadjust(a,i,n,&bh);//记住参数,进入函数 for(i=n-1;i>0;i--){//从最后节点依次走向根节点 //将节点数与根节点数交换,使得此数参与比较 int t=a[0]; a[0]=a[i]; a[i]=t; bh++; heapadjust(a,0,i,&bh); } return bh; } ///////////////////归并排序.采用分治法 为稳定排序算法 void merge(int a[],int left,int mid,int right,int *bm){ int *s=new int [right+1]; int i=left; int j=mid+1; int k=left; while(i<=mid&&j<=right){ //取出比较左半某一数据和右半某一数据,每次大的数据依次保存在 s 数组中 if(a[i]>=a[j]) s[k++]=a[i++]; else s[k++]=a[j++]; (*bm)++; } //把没有参与比较的数据(即跳出循环了)再依次存给 s 数组 while(i<=mid) {s[k++]=a[i++];(*bm)++;} while(j<=right) {s[k++]=a[j++];(*bm)++;} for(i=left;i<=right;i++) {a[i]=s[i];(*bm)++;}//将 s 数组顺序放回a中 delete []s; } int mergesort(int a[],int left,int right){ static int bm=0; if(left<right) { int mid=(left+right)/2; bm++; mergesort(a,left,mid); bm++; mergesort(a,mid+1,right); bm++; merge(a,left,mid,right,&bm); } return bm; } ///////////////////基数排序.稳定排序法、即依次比较所有数据每位数的大小,排序,有从高位开始的,也有从低位开始的 int radixsort(int a[],int n,int radixmax){ //下面所有数字即代表每位的数值,即0到9的取值 int b=0; int i,j,k=0,m=n;//由于 a 数组的数据值在1到n之间,所以可设m最大是n,使得从高位数依次向低位数排列 int (*t)[10]=new int [n][10];//动态分配的数组,第二维即是数字是0到9的象征 int tr; int order[10]={0};//0到9的数字个数数组,即,是0的数字的个数保存在数组order[0]中 while(m>=1){ for (i=0;i<n;i++){ tr=((a[i]/m)%10);//数字是tr t[order[tr]][tr]=a[i]; order[tr]++;//个数加1 b++; } //把分类的数据按照数字 0~9 的顺序返回到a中 for (i=0;i<10;i++){ if(order[i]!=0) for (j=0;j<order[i];j++){ a[k]=t[j][i]; k++; b++; } order[i]=0;//个数重新置空 } m/=10;//使得可以取得下一位数的数字 k=0; }// while循环 // for(i=0;i<n;i++) // delete []t[i]; delete []t; return b; } ///////////////////从最右向左打印 void output(int a[],int n){ int i=n; while(i--) printf("%d ",a[i]); putchar(10); } ////////////////操作函数 void operate(int a[],int n){ int *r=new int [n]; int i; double start,end; int degree; char ch; printf("请选择排序算法: "); scanf("%c",&ch); switch(ch){ case '1': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=insertsort(r,n); end=clock()/1000.0; printf("直接插入排序所用时间:\t%lf s\n",end-start); printf("直接插入排序交换次数:\t%d\n\n",degree); break; case '2': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=shellsort(r,n); end=clock()/1000.0; printf("希尔排序所用时间:\t%lf s\n",end-start); printf("希尔排序交换次数:\t%d\n\n",degree); break; case '3': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=bubblesort(r,n); end=clock()/1000.0; printf("冒泡排序所用时间:\t%lf s\n",end-start); printf("冒泡排序交换次数:\t%d\n\n",degree); start=time(NULL); break; case '4': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=quicksort(r,0,n-1); end=clock()/1000.0; printf("快速排序所用时间:\t%lf s\n",end-start); printf("快速排序交换次数:\t%d\n\n",degree); break; case '5': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=selectsort(r,n); end=clock()/1000.0; printf("直接选择排序所用时间:\t%lf s\n",end-start); printf("直接选择排序交换次数:\t%d\n\n",degree); break; case '6': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=heapsort(r,n); end=clock()/1000.0; printf("堆排序所用时间: %lf s\n",end-start); printf("堆排序交换次数: %d\n\n",degree); break; case '7': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=mergesort(r,0,n-1); end=clock()/1000.0; printf("归并排序所用时间:\t%lf s\n",end-start); printf("归并排序交换次数:\t%d\n\n",degree); break; case '8': for (i=0;i<n;i++) r[i]=a[i]; start=clock()/1000.0; degree=radixsort(r,n,10); end=clock()/1000.0; printf("基数排序所用时间:\t%lf s\n",end-start); printf("基数排序交换次数:\t%d\n\n",degree); break; case '9': return; default: printf("输入错误,请选择正确的操作!\n"); break; } getchar(); // output(r,n); //……如要看排序后结果可取消注释…… operate(a,n); } int main(){ printf("请输入要排序的个数:\t"); int n,i; scanf("%d",&n); getchar(); int *a=new int [n]; srand((unsigned int)time(NULL)); for(i=0;i<n;i++) a[i]=rand()%n+1; printf("** 排序算法比较 **\n"); printf("====================================\n"); printf("== 1 --- 直接插入排序 ==\n");//插入排序 printf("== 2 --- 希尔排序 ==\n"); printf("== ==\n"); printf("== 3 --- 冒泡排序 ==\n");//交换排序 printf("== 4 --- 快速排序 ==\n"); printf("== ==\n"); printf("== 5 --- 直接选择排序 ==\n");//选择排序 printf("== 6 --- 堆排序 ==\n"); printf("== ==\n"); printf("== 7 --- 归并排序 ==\n"); printf("== ==\n"); printf("== 8 --- 基数排序 ==\n");//分配式排序 printf("== ==\n"); printf("== 9 --- 退出程序 ==\n"); printf("====================================\n"); // output(a,n); //……如要看随机数顺序可取消注释…… operate(a,n); delete []a; return 0; }