归并排序以及三种常见优化
2020-8-16
原地归并代码
private void merge(Comparable[] a,int lo,int mid,int hi){for(int i=lo;i<=hi;i++){tep[i]=a[i];//辅助数组tep}int left=lo;//左部分开始int right=mid+1;//右部分开始元素下标for(int i=lo;i<=hi;i++){if(left>mid) a[i]=tep[right++];//左部分用完else if(right>hi) a[i]=tep[left++];//右部分用完else if(less(tep[left],tep[right])) a[i]=tep[right++];//比较大小else a[i]=tep[left++];//比较大小}
}
自顶向下:
package Algorithm;public class Merge {private boolean less(Comparable v,Comparable w){return v.compareTo(w)>0;}Comparable[] tep;public void sort(Comparable[] a){tep=new Comparable[a.length];sort(a,0,a.length-1);}private void sort(Comparable[] a,int lo,int hi){if(hi<=lo) return;int mid=lo+(hi-lo)/2;sort(a,lo,mid);sort(a,mid+1,hi);merge(a,lo,mid,hi);}private void merge(Comparable[] a,int lo,int mid,int hi){for(int i=lo;i<=hi;i++){tep[i]=a[i];//辅助数组tep}int left=lo;//左部分开始int right=mid+1;//右部分开始元素下标for(int i=lo;i<=hi;i++){if(left>mid) a[i]=tep[right++];//左部分用完else if(right>hi) a[i]=tep[left++];//右部分用完else if(less(tep[left],tep[right])) a[i]=tep[right++];//比较大小else a[i]=tep[left++];//比较大小}}
}
自底向上:
可用于链表排序
public void sort(Comparable[] a){tep=new Comparable[a.length];int n=a.length;for (int sz= 1; sz<n; sz=sz+sz) {//sz,数组大小(从0计算,o-5,则sz=5)for (int lo=0;lo<n-sz;lo+=sz+sz){//lo,数组开始下标。每次lo=lo+sz+sz,合并两个数组大小merge(a,lo,lo+sz-1,Math.min(n-1,lo+sz+sz-1));}}}
三种优化
1.小规模数组采用插入排序
private void sort(Comparable[] a,int lo,int hi){if(hi<=lo) return;if(hi-lo<=7){//小规模采用插入排序**********for(int i=lo;i<=hi;i++){for(int j=i;j>lo;j--){if(a[j].compareTo(a[j-1]<0)){Comparable t=a[j];a[j]=a[j-1];a[j-1]=t;}}}}int mid=lo+(hi-lo)/2;sort(a,lo,mid);sort(a,mid+1,hi);merge(a,lo,mid,hi);}
2.合并时判断是否有序
private void sort(Comparable[] a,int lo,int hi){if(hi<=lo) return;int mid=lo+(hi-lo)/2;sort(a,lo,mid);sort(a,mid+1,hi);****if(a[mid].compareTo(a[mid+1])<=0) return;*****//判断是否有序merge(a,lo,mid,hi);}
3.优化辅助数组时的时间
注意空间不能优化
将此辅助数组变为在递归中的参数即可。这样的话,上面两个代码都要改变。
package Algorithm;public class Merge {private boolean less(Comparable v,Comparable w){return v.compareTo(w)>0;}private void exch(Comparable[] a,int i,int j){Comparable t=a[i];a[i]=a[j];a[j]=t;}public void sort(Comparable[] a){Comparable[] tep=a.clone();sort(tep,a,0,a.length-1);}private void sort(Comparable[] src, Comparable[] dst, int lo, int hi){if(hi<=lo) return;if(hi<=lo+7){for(int i=lo;i<=hi;i++){for(int j=i;j>lo;j--){if(less(dst[j-1],dst[j])){exch(dst,j,j-1);}}}return;}int mid=lo+(hi-lo)/2;sort(dst,src,lo,mid);sort(dst,src,mid+1,hi);if(less(src[mid+1],src[mid])){System.arraycopy(src,lo,dst,lo,hi-lo+1);return;}merge(src,dst,lo,mid,hi);}private void merge(Comparable[] src,Comparable[] dst,int lo,int mid,int hi){int left=lo;//左部分开始int right=mid+1;//右部分开始元素下标for(int i=lo;i<=hi;i++){if(left>mid) dst[i]=src[right++];//左部分用完else if(right>hi) dst[i]=src[left++];//右部分用完else if(less(src[left],src[right])) dst[i]=src[right++];//比较大小else dst[i]=src[left++];//比较大小}}
}
参考自:https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/MergeX.java
2019-4-23
分解:将待排序的n个元素分成n/2两个子序列
解决:使用归并排序递归的排序两个子序列
合并:合并两个已排序好的子序列来生成排序好的答案。
当待排序的序列长度为1时,递归回升,因为这时长度为1的序列,已经排序好了。我们不需要任何操作。
这里讲一下具体操作:将要排序的一组数分成两堆(这里我们选取中间点为划分标准),然后我们从两堆中的第一个元素比较,小的(或者大的,这里要求我们是降序还是升序排列)就放到一个新开的数组里面,来保存我们所需要的答案。
#include<stdio.h>
void MERGE(int *num,int p,int q,int r)
{int n1,n2;//两边各多少个元素 n1=q-p+1;n2=r-q;int am[50]={0};int ab[50]={0};for(int i=0;i<n1;i++){am[i]=num[p+i];}am[n1]=0x3f3f3f3f;//作为结束的哨兵for(int i=0;i<n2;i++){ab[i]=num[q+1+i];}ab[n2]=0x3f3f3f3f;int j=0;int i=0;//分别是两个待排序数组的下标for(int k=p;k<=r;k++)//从p到r,保证了所有元素都被排序{if(am[i]<=ab[j]){num[k]=am[i];i++;}else{num[k]=ab[j];j++;}}
}
void MERGE_SORT(int *num,int p,int r)
{if(p<r){int q=(p+r)/2;MERGE_SORT(num,p,q);MERGE_SORT(num,q+1,r);MERGE(num,p,q,r);}
}
int main(void)
{int num[50]={96,1,2,3,66,805,45,63,67,59,57,50,52,23,24};//15个printf("排序前\n");for(int j=0; j<=14; j++){printf("%d ",num[j]);}putchar('\n');MERGE_SORT(num,0,14);printf("排序后\n");for(int j=0; j<=14; j++){printf("%d ",num[j]);}putchar('\n');}
`
归并排序以及三种常见优化相关推荐
- 服务器三种常见的限流算法
服务器三种常见的限流算法 1.计数器算法 2. 滑动窗口 3.令牌桶算法 4.漏桶算法 滑动窗口限流 漏桶限流 令牌桶限流 限流算法总结 单机限流和分布式限流 限流组件 在开发高并发系统时,有三把利器 ...
- html中选择样式,html中css三种常见的样式选择器 zz
1:标签选择器 标签选择器,是所有带有某种标签的都生效.这里以p为例,也就是所有的带有p标记的都会这样的样式 p{font:"宋体"; color:#FF0000} 我现在表现的是 ...
- 三种常见的Python赋值表达式的写法!
Python的赋值表达式英文原名为Assignment Expressions,因为它太像海象了所以又被称为海象运算符.今天小千就来给大家介绍一下三种常见的赋值表达式的写法,大家来了解一下以防将来遇到 ...
- C语言三种常见排序算法
该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105112802 三 ...
- xp系统蓝屏代码7b_遇到系统问题,三种常见处理方法你更pick谁
使用恢复功能之前请务必备份好数据,一旦操作可能导致数据无法恢复!!!卡慢.蓝屏.进不去系统?系统出现故障了,是拜托朋友还是外出花钱?求人不如求己,遇到系统问题 , 三种常见处理方法你更pick谁? 0 ...
- 深入学习jQuery的三种常见动画效果
前面的话 动画效果是jQuery吸引人的地方.通过jQuery的动画方法,能够轻松地为网页添加视觉效果,给用户一种全新的体验.jQuery动画是一个大的系列,本文将详细介绍jQuery的三种常见动画效 ...
- php给html传值,PHP传值到不同页面的三种常见方式及php和html之间传值问题_PHP
在项目开发中经常见到不同页面之间传值在web工作中,本篇文章给大家列出了三种常见的方式. 接触PHP也有几个月了,本文总结一下这段日子中,在编程过程里常用的3种不同页面传值方法,希望可以给大家参考.有 ...
- java常见的ide_在三个Java IDE中生成的三种常见方法
java常见的ide 在本文中,我研究了NetBeans 8.0.2 , IntelliJ IDEA 14.0.2和Eclipse Luna 4.4.1生成的三种"通用"方法[ e ...
- 在三个Java IDE中生成的三种常见方法
在本文中,我研究了NetBeans 8.0.2 , IntelliJ IDEA 14.0.2和Eclipse Luna 4.4.1生成的三种"通用"方法[ equals(Objec ...
最新文章
- android 耳机红外线,红外线耳机制作方法
- 利用 Vmware 安装 Linux 虚拟机
- [书籍分享]0-003.你的灯亮着吗:发现问题的真正所在
- 老员工在线“黑”华为:早期手机难看丢人 习惯另外带苹果三星
- linux java xmx_linux应用实际内存大于 jvm xmx
- 华为交换机重制_华为交换机重置命令
- pypdf2 存储pdf_PyPDF2:用于PDF文件操作的Python库
- 10个修复ie6下bug技巧[转]
- 心电电路算法滤波_简述心电信号采集原理及电路设计
- Keil4 新建工程 和 烧录程序
- Unity Shader 标准光照模型——漫反射
- Python第五周作业之选择题
- vue-router 如何在新窗口打开页面
- python request下载文件时、显示进度以及网速_实时网速显示_实例_python
- 呆老大,奸老二,家家有个坏老三(转载自:http://soulogic.3322.org/blog/read.php/165.html)
- 2015小米校招技术类笔试题
- 流程图-一些要点总结
- 通过宏代码自动解除excel工作表格保护
- python中文词频排序_python统计词频并排序
- python quit函数_在Python中启用quit函数的问题