数据结构(四十七)归并排序(O(nlogn))
一、归并排序的定义
归并排序(Merging Sort)就是利用归并的思想实现的排序方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到【n/2】个长度为2或1的有序子序列;再两两归并,...,如此反复,直到得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。

二、归并排序算法的实现
private static void merge(int[] a, int[] swap, int k) {
int n = a.length;
int m = 0, i, j;
int end1, start2, end2;
int start1 = 0; // 第一个有序子数组下界
while (start1 + k <= n - 1) {
start2 = start1 + k; // 第二个有序子数组下界
end1 = start2 - 1; // 第一个有序子数组上界
end2 = (start2 + k - 1 <= n - 1)? start2 + k - 1 : n - 1; // 第二个有序子数组上界
for (i = start1, j = start2; i <= end1 && j <= end2; m++) { // 将k-1个数从小到大排列并写入swap数组
if (a[i] <= a[j]) {
swap[m] = a[i];
i++;
} else {
swap[m] = a[j];
j++;
}
}
while (i <= end1) { // 如果i越界就把k个数中值最大的放在swap数组的区间数组最后一位
swap[m] = a[i];
m++;
i++;
}
while (j <= end2) { // 如果j越界就把k个数中值最大的放在swap数组的区间数组最后一位
swap[m] = a[j];
m++;
j++;
}
start1 = end2 + 1; // 从下一个k区间的第一个数开始
}
for (i = start1; i < n; i++, m++) { // 将原始数组中只够一组的数据元素顺序存放到数组swap中
swap[m] = a[i];
}
}
public static void mergeSort(int[] a) {
int k = 1; // 归并长度从1开始
int[] swap = new int[a.length];
while (k < a.length) {
merge(a, swap, k);
for (int i = 0; i < a.length; i++) { // 将调整后的元素重新放回原始数组中
a[i] = swap[i];
}
System.out.print("k值为" + k + "时: ");
print(a);
k = 2 * k; // 归并长度为原来的二倍
}
}
结合代码分析代码执行过程
int[] array1 = {50,10,90,30,70,40,80,60,20};
k=1时,swap={0,0,0,0,0,0,0,0,0},执行merge方法,
m=0,start1=0且0+1<=8进入while,start2=1,end1=0,end2=1,
进入for循环,i=0,j=1,a0=50,a1=10,swap[0]=10,j=2,m=1,j<=end2不成立,跳出for,进入i的while,swap[1]=50,m=2,i=1,start1=2,也就是交换50和10并放入swap数组的前两位
m=2,start1=2且2+1<=8进入while,start2=3,end1=2,end2=3,
进入for循环,i=2,j=3,a2=90,a3=30,swap[2]=30,j=4,m=3,j<=end2不成立,跳出for,进入i的while,swap[3]=90,m=4,i=2,start1=4,也就是交换90和30并放入swap数组的前两位
同理,交换70和40,交换80和60,然后a[]=swap[]={10 50 30 90 40 70 60 80 20}
k=2时,swap={10,50,30,90,40,70,60,80,20},执行merge方法,
m=0,start1=0且0+2<=8进入while,start2=2,end1=1,end2=3,
进入for循环,i=0,j=2,a0=10,a2=30,swap[0]=10,i=1,m=1,
进入for循环,i=1,j=2,a1=50,a2=30,swap[1]=30,j=3,m=2,
进入for循环,i=1,j=3,a1=50,a3=90,swap[2]=50,i=2,m=3
i=2<=end1不成立,跳出for,进入j的while,j=3<=3.swap[3]=a3=90,也就是将数组的前四位按顺序排列即将10 50 30 90变成10 30 50 90
同理,将40 70 60 80变成40 60 70 80
其他同理:
k值为4时: 10 30 40 50 60 70 80 90 20
k值为8时: 10 20 30 40 50 60 70 80 90
过程用图片表示为:



测试代码和输出为:
public static void main(String[] args) {
int[] array1 = {50,10,90,30,70,40,80,60,20};
System.out.print("归并排序前: ");
print(array1);
mergeSort(array1);
System.out.print("归并排序后: ");
print(array1);
}
归并排序前: 50 10 90 30 70 40 80 60 20
k值为1时: 10 50 30 90 40 70 60 80 20
k值为2时: 10 30 50 90 40 60 70 80 20
k值为4时: 10 30 40 50 60 70 80 90 20
k值为8时: 10 20 30 40 50 60 70 80 90
归并排序后: 10 20 30 40 50 60 70 80 90
三、归并排序算法的性能分析
(1)时间复杂度
示例中有9个数时,k的值分别为1,2,4,8,即需要进行4次归并,
则n个元素进行归并排序算法时需要进行【logn】+1次归并运算,而每一次归并运算内比较的次数都为n-1,所以二路归并排序算法的时间复杂度为O(nlogn)。。
对于归并排序来说,最好、最坏、平均情况下的时间复杂度均为O(nlogn)。
(2)空间复杂度
由于二路归并排序时使用了n个临时内存空间存放数据元素,所以,二路归并排序算法的空间复杂度为O(n)。
(3)稳定性
由于二路归并排序算法是相邻有序子表两两归并,对于相同的两个数据元素,则能够保证原来在前边的元素排序后仍在前边。因此,二路归并排序算法是一种稳定的排序算法。
二路排序算法不仅时间复杂度是O(nlogn),而且还是一种稳定的排序算法,这一点是二路归并排序算法的最大特点。
数据结构(四十七)归并排序(O(nlogn))的更多相关文章
- NeHe OpenGL教程 第四十七课:CG顶点脚本
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- 学习javascript数据结构(四)——树
前言 总括: 本文讲解了数据结构中的[树]的概念,尽可能通俗易懂的解释树这种数据结构的概念,使用javascript实现了树,如有纰漏,欢迎批评指正. 原文博客地址:学习javascript数据结构( ...
- Gradle 1.12用户指南翻译——第四十七章. Build Init 插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- Java进阶(四十七)Socket通信
Java进阶(四十七)Socket通信 今天讲解一个 Hello Word 级别的 Java Socket 通信的例子.具体通讯过程如下: 先启动Server端,进入一个死循环以便一直监听某端口是 ...
- SQL注入之Sqli-labs系列第四十七关,第四十八关,第四十九关(ORDER BY注入)
0x1 源码区别点 将id变为字符型:$sql = "SELECT * FROM users ORDER BY '$id'"; 0x2实例测试 (1)and rand相结合的方式 ...
- C# 优化程序的四十七种方法
一.用属性代替可访问的字段 1..NET数据绑定只支持数据绑定,使用属性可以获得数据绑定的好处: 2.在属性的get和set访问器重可使用lock添加多线程的支持. 二.readonly(运行时常量) ...
- 《构建之法》第四&十七章读书笔记
<构建之法>第四&十七章读书笔记 一. 前言 再次阅读<构建之法>,愈发被其中生动有趣的举例吸引.作为一本给予软件工程学生的书籍,其不以枯燥的理论知识 ...
- “全栈2019”Java第四十七章:继承与方法
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 孤荷凌寒自学python第四十七天通用跨数据库同一数据库中复制数据表函数
孤荷凌寒自学python第四十七天通用跨数据库同一数据库中复制数据表函数 (完整学习过程屏幕记录视频地址在文末) 今天继续建构自感觉用起来顺手些的自定义模块和类的代码. 今天打算完成的是通用的(至少目 ...
- noi2019模拟测试赛(四十七)
noi2019模拟测试赛(四十七) T1与运算(and) 题意: 给你一个序列\(a_i\),定义\(f_i=a_1\&a_2\&\cdots\&a_i\),求这个序列的所 ...
随机推荐
- IDEA加密算法(含所需jar包(commons-codec-1.11.jar ,bcprov-jdk15on-160.jar))
软件设计上机实验IDEA算法: import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.Se ...
- 品Spring:SpringBoot和Spring到底有没有本质的不同?
现在的Spring相关开发都是基于SpringBoot的. 最后在打包时可以把所有依赖的jar包都打进去,构成一个独立的可执行的jar包.如下图13: 使用java -jar命令就可以运行这个独立的j ...
- cp -rf 操作时依然会提示覆盖
在linux上经常会使用cp -rf命令,该命令就是强制覆盖指定目录下的文件,但有时使用该命令依然会提示是否覆盖,cp命令的参数有如下一些: 参数说明: -a:此选项通常在复制目录时使用,它保留链接. ...
- <<Java并发编程的艺术>>-阅读笔记和思维导图
最近在坚持每天阅读<>,不但做好笔记(MarkDown格式),还做好思维导图. 如果大家感兴趣,可以可以到码云上阅读笔记和到ProcessOn上阅读思维导图. 码云:https://git ...
- 13.Django基础之django分页
一.Django的内置分页器(paginator) view from django.shortcuts import render,HttpResponse # Create your views ...
- 使用 Sealos 在 3 分钟内快速部署一个生产级别的 Kubernetes 高可用集群
本文首发于:微信公众号「运维之美」,公众号 ID:Hi-Linux. 「运维之美」是一个有情怀.有态度,专注于 Linux 运维相关技术文章分享的公众号.公众号致力于为广大运维工作者分享各类技术文章和 ...
- selenium+testNG自动化测试框架搭建
自动化测试框架搭建 1 Java环境的搭建 1.1访问oracle的官网下载最新版本的jdk http://www.oracle.com/technetwork/java/javase/downloa ...
- bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...
- Windows 10 更新后VMware Workstation pro无法运行 (无需卸载原版本VM)
问题 描述:当前Windows版本是win10-1903,VMware版本比较老旧是VMware Workstation Pro 15.0.4:国庆节后微软推送了一个新的更新补丁,10月10日更新之后 ...
- bugku color
下载打开压缩包是七张图片,分别是七个颜色,使用stegsolve打开发现了异常. 七张图片拼起来是 make me tall,看来是要修改图片高度. 我们使用winhex打开图片并在十六进制中修改图片 ...