算法 基于比较的排序
2014-03-06 16:55
429 查看
插入排序
生活中可以用来模拟插入排序的事件,例如打牌中的将牌排序,十分形象具体
通常情况下插入排序O(N^2),基本有序(最好情况下)时是O(N),是稳定排序
折半插入排序可以在比较次数上进行优化,但移动次数未改变,复杂度仍然是O(N^2)
2-路插入排序
表插入排序
希尔SHELL排序
SHELL排序是不稳定的排序,
通常情况下性能优于插入排序
快速排序
快速排序基于分治法的排序算法,
时间复杂度为O(n*logn),基本有序的情况下(也就是最坏情况下)是O(n^2),但通常情况下性能是最佳的,常数因子较小
不稳定排序
为了避免基本有序的情况,通过引入随机化技术,使得在等概率的情况下获得期望性能,所作的操作只需要随机一个位置与每次作pivot的位置元素交换;
另外一种改进随机是三数取中划分,随机三个位置,然后取中位数为pivot
堆排序
堆排序的前身:树形选择排序,又称锦标赛排序(类似比赛分组树结构)
堆的定义是:一个完全二叉树,每个结点大于等于其两个孩子结点(大根堆)
堆排序的过程,首先建堆,然后将堆顶与末尾元素交换,紧接着调整堆使其继续保持定义,循环交换n次,形成最终有序排列
时间复杂度O(n*logn),其中调整堆的复杂度为O(logn),排序O(n),不稳定排序
堆排序的应用:
优先队列
归并排序
归并排序的时间复杂度最好最坏下均是O(n*logn),但空间复杂度是O(n)
是稳定排序
利用递归树可以清晰地分析归并排序的过程
void insert_sort(int *ary,int n) { int temp; int i,j; for(i=1;i<n;i++)// 从第二个数开始 { temp=ary[i]; for(j=i;j>0&&temp<ary[j-1];j--) { ary[j]=ary[j-1]; } ary[j]=temp; } }
生活中可以用来模拟插入排序的事件,例如打牌中的将牌排序,十分形象具体
通常情况下插入排序O(N^2),基本有序(最好情况下)时是O(N),是稳定排序
折半插入排序可以在比较次数上进行优化,但移动次数未改变,复杂度仍然是O(N^2)
2-路插入排序
表插入排序
希尔SHELL排序
int shell_sort(int *ary,int size) { int op=0; int temp; int incs[5]={1,5,19,41,109}; for(int t=4;t>=0;t--) { int h=incs[t]; for(int i=h;i<size;i++) { temp=ary[i]; for(j=i;j>0&&temp<ary[j-h];j=j-h) { ary[j]=ary[j-h]; op++; } ary[j]=temp; op++; } } return op; ]
SHELL排序是不稳定的排序,
通常情况下性能优于插入排序
快速排序
// 从左遍历版本,以结尾为主元,返回的轴位置为i+1,因为这里i是从-1开始移动的 int partition(int *ary,int left,int right) { int i=left-1; int j=left; int pivot=ary[right]; for(;j<right;j++) { if(ary[j]<=pivot) { i++; swap(i,j); } } swap(i+1,right); return i+1; } void quick_sort(int *ary,int left,int right) { if(left<right) { int index=partition(ary,left,right); quick_sort(ary,left,index-1); quick_sort(ary,index+1,right); } } // HOARE版本,可以任意位置为主元,这里返回的轴位置是j+1,最后j在i前,可能j+1=i也可能j+2=i void quicksort(int *ary,int left,int right) { if(left<right){ int i=left,j=right; int pivot=ary[left]; while(i<=j){ while(ary[j]>pivot)j--; while(ary[i]<pivot)i++; if(i<=j){ int temp=ary[i]; ary[i]=ary[j]; ary[j]=temp; i++;j--; } } if(left<j) quicksort(ary,left,j); if(i<right) quicksort(ary,i,right); } } // 替换版本,非交换版本,这里返回的轴位置是i void quicksort(int *ary,int left,int right) { if(left<right){ int i=left; int j=right; int key=ary[i]; while(i<j) { while(i<j&&ary[j]>=key)j--; ary[i]=ary[j]; while(i<j&&ary[i]<=key)i++; ary[j]=ary[i]; } ary[i]=key; if(left<i-1) quicksort(ary,left,i-1);// 这里可以用i-1,因为ary[i]已经在有序的位置上了 if(i+1<right) quicksort(ary,i+1,right); } }
快速排序基于分治法的排序算法,
时间复杂度为O(n*logn),基本有序的情况下(也就是最坏情况下)是O(n^2),但通常情况下性能是最佳的,常数因子较小
不稳定排序
为了避免基本有序的情况,通过引入随机化技术,使得在等概率的情况下获得期望性能,所作的操作只需要随机一个位置与每次作pivot的位置元素交换;
另外一种改进随机是三数取中划分,随机三个位置,然后取中位数为pivot
堆排序
void swap(int *a,int *b) { int temp=*a; *a=*b; *b=temp; } // 调整堆 siftdown void heapify(int *ary,int i,int size) { int left,right,max; while(i<size) { left=2*i+1; right=left+1; max=i; if(left<size&&ary[i]<ary[left]) i=left; if(right<size&&ary[i]<ary[right]) i=right; if(i!=max) swap(&ary[i],&ary[max]); else break; } } // 建堆 siftup void buildHeap(int *ary,int size) { for(int i=(size-2)/2;i>=0;i--)// 利用siftdown实现siftup,FOR 每个结点的父母结点 TO 根结点 { heapify(ary,i,size); } } // 堆排序过程 ,先建堆,然后交换顶点与末尾,交换一次再调整一次,当前代码是大根堆,所以最后顺序是从小到大 void heapSort(int *ary,int size) { buildHeap(ary,size); for(int i=size-1;i>0;i--) { swap(&ary[0],&ary[i]); heapify(ary,0,i); } }
堆排序的前身:树形选择排序,又称锦标赛排序(类似比赛分组树结构)
堆的定义是:一个完全二叉树,每个结点大于等于其两个孩子结点(大根堆)
堆排序的过程,首先建堆,然后将堆顶与末尾元素交换,紧接着调整堆使其继续保持定义,循环交换n次,形成最终有序排列
时间复杂度O(n*logn),其中调整堆的复杂度为O(logn),排序O(n),不稳定排序
堆排序的应用:
优先队列
归并排序
// 归并排序,不过new和delete写在子函数中,效率可能不高,可以直接在排序前申请O(n)的空间 void mergeArray(int *ary,int left,int mid,int right,int *temp) { int i=left,j=mid+1,k=0; int temp[]=new int[right-left+1]; while(i<mid&&j<right) { if(ary[i]<ary[j]) temp[k++]=ary[i++]; else temp[k++]=ary[j++]; } while(i<=mid) temp[k++]=ary[i++]; while(j<=right) temp[k++]=ary[j++]; // 复制回原数组 for(int i=0;i<k;i++) { ary[left+i]=temp[i]; } // 考虑是否删除额外空间 delete[] temp; } void mergeSort(int *ary,int left,int right,int *temp) { int mid=((right-left)>>1)+left; if(left<right) { mergeSort(ary,left,mid);//注意这里不是 mid-1,之前写错了 mergeSort(ary,mid+1,right); mergeArray(ary,left,mid,right,temp); } }
归并排序的时间复杂度最好最坏下均是O(n*logn),但空间复杂度是O(n)
是稳定排序
利用递归树可以清晰地分析归并排序的过程
相关文章推荐
- 非基于比较的排序算法之一:计数排序
- 为什么说任何基于比较的算法将 5 个元素排序都需要 7 次?
- 基于比较的算法之四:快速排序
- 为什么说任何基于比较的算法将 5 个元素排序都需要 7 次?
- 为什么说任何基于比较的算法将 5 个元素排序都需要 7 次?
- 基于比较的算法之二:选择排序
- 【算法】排序 (三):二叉树排序&基于散列排序(C++实现)
- stl的排序 和 用算法实现的排序比较
- 设定二维整数数组B[0..m-1,0..n-1]的数据在行,列方向上都按从小到大的顺序排序,且整形变量x中的数据在B中存在。设计一个算法,找出一对满足B[i][j]=x的I,j值,要求比较次数不超过m
- 基于比较的算法之三:插入排序
- 基于JAVA的排序算法之十--几种排序…
- STL学习记录(十三):排序类算法及基于排序的算法
- 【排序结构5】 基于比较的内部排序总结
- c语言中冒泡排序、插入排序、选择排序算法比较
- c语言中冒泡排序、插入排序、选择排序算法比较
- 算法学习笔记之排序--基于指针的插入排序
- 【数据结构】非比较排序的算法实现(包括计数排序、计数排序)
- LCD圆弧绘制算法~基于逐点比较算法,入口参数:弧线起点、终点(逆时针方向)、圆心
- 线性时间排序: 三种非基于比较的内部排序算法
- 算法实践篇-基于计数排序的基数排序