归并排序 java_马士兵说之归并排序

大家对于排序应该是挺熟悉的吧,马士兵老师特意为排序出了一波视频,当然文章是转自博客园的,马士兵老师的视频观看请点击下方的了解更多

概要

本章介绍排序算法中的归并排序。内容包括:

1. 归并排序介绍

2. 归并排序图文说明

3. 归并排序的时间复杂度和稳定性

4. 归并排序实现

4.1 归并排序C实现

4.2 归并排序C++实现

4.3 归并排序Java实现


更多排序和算法请参考:数据结构与算法系列 目录

归并排序介绍

将两个的有序数列合并成一个有序数列,我们称之为"归并"。

归并排序(Merge Sort)就是利用归并思想对数列进行排序。根据具体的实现,归并排序包括"从上往下"和"从下往上"2种方式。

1. 从下往上的归并排序:将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。这样就得到了我们想要的排序结果。(参考下面的图片)

2. 从上往下的归并排序:它与"从下往上"在排序上是反方向的。它基本包括3步:

① 分解 -- 将当前区间一分为二,即求分裂点 mid = (low + high)/2;

② 求解 -- 递归地对两个子区间a[low...mid] 和 a[mid+1...high]进行归并排序。递归的终结条件是子区间长度为1。

③ 合并 -- 将已排序的两个子区间a[low...mid]和 a[mid+1...high]归并为一个有序的区间a[low...high]。

下面的图片很清晰的反映了"从下往上"和"从上往下"的归并排序的区别。

60f6b57c8d0ab0f9e776259a6905c863.png

归并排序图文说明

归并排序(从上往下)代码

/* * 将一个数组中的两个相邻有序区间合并成一个 * * 参数说明: * a -- 包含两个有序区间的数组 * start -- 第1个有序区间的起始地址。 * mid -- 第1个有序区间的结束地址。也是第2个有序区间的起始地址。 * end -- 第2个有序区间的结束地址。 */void merge(int a[], int start, int mid, int end){ int *tmp = (int *)malloc((end-start+1)*sizeof(int)); // tmp是汇总2个有序区的临时区域 int i = start; // 第1个有序区的索引 int j = mid + 1; // 第2个有序区的索引 int k = 0; // 临时区域的索引 while(i <= mid && j <= end) { if (a[i] <= a[j]) tmp[k++] = a[i++]; else tmp[k++] = a[j++]; } while(i <= mid) tmp[k++] = a[i++]; while(j <= end) tmp[k++] = a[j++]; // 将排序后的元素,全部都整合到数组a中。 for (i = 0; i < k; i++) a[start + i] = tmp[i]; free(tmp);}/* * 归并排序(从上往下) * * 参数说明: * a -- 待排序的数组 * start -- 数组的起始地址 * endi -- 数组的结束地址 */void merge_sort_up2down(int a[], int start, int end){ if(a==NULL || start >= end) return ; int mid = (end + start)/2; merge_sort_up2down(a, start, mid); // 递归排序a[start...mid] merge_sort_up2down(a, mid+1, end); // 递归排序a[mid+1...end] // a[start...mid] 和 a[mid...end]是两个有序空间, // 将它们排序成一个有序空间a[start...end] merge(a, start, mid, end);}

从上往下的归并排序采用了递归的方式实现。它的原理非常简单,如下图:

491c578ef9a82c4faaa785779803912b.png

通过"从上往下的归并排序"来对数组{80,30,60,40,20,10,50,70}进行排序时:

1. 将数组{80,30,60,40,20,10,50,70}看作由两个有序的子数组{80,30,60,40}和{20,10,50,70}组成。对两个有序子树组进行排序即可。

2. 将子数组{80,30,60,40}看作由两个有序的子数组{80,30}和{60,40}组成。

将子数组{20,10,50,70}看作由两个有序的子数组{20,10}和{50,70}组成。

3. 将子数组{80,30}看作由两个有序的子数组{80}和{30}组成。

将子数组{60,40}看作由两个有序的子数组{60}和{40}组成。

将子数组{20,10}看作由两个有序的子数组{20}和{10}组成。

将子数组{50,70}看作由两个有序的子数组{50}和{70}组成。

归并排序(从下往上)代码

/* * 对数组a做若干次合并:数组a的总长度为len,将它分为若干个长度为gap的子数组; * 将"每2个相邻的子数组" 进行合并排序。 * * 参数说明: * a -- 待排序的数组 * len -- 数组的长度 * gap -- 子数组的长度 */void merge_groups(int a[], int len, int gap){ int i; int twolen = 2 * gap; // 两个相邻的子数组的长度 // 将"每2个相邻的子数组" 进行合并排序。 for(i = 0; i+2*gap-1 < len; i+=(2*gap)) { merge(a, i, i+gap-1, i+2*gap-1); } // 若 i+gap-1 < len-1,则剩余一个子数组没有配对。 // 将该子数组合并到已排序的数组中。 if ( i+gap-1 < len-1) { merge(a, i, i + gap - 1, len - 1); }}/* * 归并排序(从下往上) * * 参数说明: * a -- 待排序的数组 * len -- 数组的长度 */void merge_sort_down2up(int a[], int len){ int n; if (a==NULL || len<=0) return ; for(n = 1; n < len; n*=2) merge_groups(a, len, n);}

从下往上的归并排序的思想正好与"从下往上的归并排序"相反。如下图:

0d43fa7221adca847783c2c033dc0181.png

通过"从下往上的归并排序"来对数组{80,30,60,40,20,10,50,70}进行排序时:

1. 将数组{80,30,60,40,20,10,50,70}看作由8个有序的子数组{80},{30},{60},{40},{20},{10},{50}和{70}组成。

2. 将这8个有序的子数列两两合并。得到4个有序的子树列{30,80},{40,60},{10,20}和{50,70}。

3. 将这4个有序的子数列两两合并。得到2个有序的子树列{30,40,60,80}和{10,20,50,70}。

4. 将这2个有序的子数列两两合并。得到1个有序的子树列{10,20,30,40,50,60,70,80}。

归并排序的时间复杂度和稳定性

归并排序时间复杂度

归并排序的时间复杂度是O(N*lgN)。

假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?

归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它的时间复杂度是O(N*lgN)。

归并排序稳定性

归并排序是稳定的算法,它满足稳定算法的定义。

算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

归并排序实现

下面给出归并排序的三种实现:C、C++和Java。这三种实现的原理和输出结果都是一样的,每一种实现中都包括了"从上往下的归并排序"和"从下往上的归并排序"这2种形式。

归并排序C实现

实现代码(merge_sort.c)

View Code

归并排序C++实现

实现代码(MergeSort.cpp)

View Code

归并排序Java实现

实现代码(MergeSort.java)

View Code

上面3种实现的原理和输出结果都是一样的。下面是它们的输出结果:

before sort:80 30 60 40 20 10 50 70 after sort:10 20 30 40 50 60 70 80 

文章原作者:http://www.cnblogs.com/skywang12345/p/3602369.html

ed6864bbc2b43cb57d6d707663f938c7.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/501214.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tft lcd驱动参数详解_LED拼接屏和LCD拼接屏的区别

LED屏幕和LCD屏幕是每个人都经常听到的两个屏幕&#xff0c;但是每个人之间的区别尚不清楚。不认识的人可能会认为两者之间没有区别。让我们谈谈LED和LCD屏幕之间的区别&#xff1a;首先&#xff0c;什么是LED&#xff1f; LED是发光二极管&#xff0c;LED拼接屏是由发光二极管…

求有向图的简单路径_2020福建农信社招聘-关键路径

2020福建农信社公告暂未发布&#xff0c;预计于2020年1月发布公告&#xff0c;历年福建农信社笔试以纸考形式进行&#xff0c;同时笔试内容包含经济、金融、计算机、法律、财会、公基、三农、农信文化、普惠金融、市场营销、时政等部分&#xff0c;相对而言考试知识点较多&…

cad插件_CAD插件自动编号安装教程

插件下载[名称]&#xff1a;CAD插件-自动编号[大小]&#xff1a;3.67MB [语言]&#xff1a;简体中文 [安装环境]&#xff1a;Win7/Win8/Win10[支持版本]&#xff1a;CAD2004-2020[32/64位下载链接]&#xff1a;pan.baidu.com/s/1XACgkA4OTrsk08QdGQB9RQ[提取码]: 8327安装中有…

Nginx的初步安装

目录 Nginx的初步安装 1.使用远程连接工具连接Linux操作系统 2.因为是开源的&#xff0c;所以可以去官网直接下载 3.安装Nginx前需要安装一些相关的依赖包 第一步&#xff1a;&#xff08;用第一种方式&#xff1a;wget的方式&#xff09;安装pcre 第二步&#xff1a;安装…

苹果手机电越充越少怎么回事_手机充着电,电量缺越来越少是怎么回事?

手机充电状态下越充越少一般由以下几个方面原因造成&#xff1a;手机系统故障&#xff0c;因此导致电池电量显示出现问题。充电器出现故障。充电器和手机接触不良。手机电池出现问题。手机本身存在质量问题。解决方法&#xff1a;手机系统故障&#xff0c;因此导致电池电量显示…

串口助手驱动_STM32Cube22(补充) | 使用硬件I2C驱动OLED(SSD1306)

点上方蓝字关注我们每天都有好玩的东西等着你本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外设驱动0.96OLED屏幕。1. 准备工作硬件准备开发板首先需要准备一个开发板&#xff0c;这里我准备的是STM32L4的开发板(BearPi)&#xff1a;OLED屏幕这里我使用的是0…

Nginx的开启和关闭

目录 Nginx操作的常用命令 1.首先进入Nginx的目录 2.查看Nginx的版本号 3.启动Nginx 4.关闭Nginx 5.重新加载Nginx Nginx操作的常用命令 1.首先进入Nginx的目录 /usr/local/nginx/sbin 2.查看Nginx的版本号 3.启动Nginx 查看进程状态&#xff1a;是否有nginx进程启动 4…

jq 通过标签名称获取标签_如何快速通过今日头条原创标签的审核?

拥有头条自媒体的作者越来越多&#xff0c;未来可能会有更多的人拥有自媒体平台&#xff0c;但真正能够获得平台授予的原创标签的作者&#xff0c;恐怕是少了许多&#xff0c;头条号对于原创标签的审核尤为严格&#xff0c;如何快速通过原创标签的申请&#xff0c;下面为大家分…

Nginx的配置文件

目录 Nginx的配置文件 1.找到Nginx配置文件的位置 2.Nginx配置文件组成 第一部分&#xff1a;全局块 第二部分&#xff1a;events块 第三部分&#xff1a;http块 &#xff08;1&#xff09;http 全局块 &#xff08;2&#xff09;server 块 Nginx的配置文件 1.找到Ngin…

C++为什么空格无法输出_OOP 面向对象编程:由 C 到 C++

作者&#xff1a;鲸90830链接&#xff1a;https://www.cnblogs.com/whale90830/p/10488595.html由C到COOP第一课C语言的局限C的特点C的程序特征C程序的结构特性C程序的编辑、编译和运行⭐C对C的补充C语言的局限类型检查机制相对较弱&#xff0c;使得程序中的一些错误不能在编译…

idea无法导入主题jar包_总结IDEA开发的26个常用设置

IDEA 软件设置Settings页面Settings是对软件本身的一些属性进行配置&#xff0c;例如字体 主题 背景图 插件等。如何打开Settings设置页面Settings设置页面结构详解结构Appearance & Behavior 外观和行为Keymap 快捷键Editor 编辑器设置Plugins 插件Version Control 版本控…

Nginx的配置实例(反向代理准备工作)

目录 反向代理准备工作 1.实现效果 2.准备工作 &#xff08;1&#xff09;在 Linux 系统中安装 tomcat 服务器&#xff0c;使用默认端口号 &#xff08;2&#xff09;设置对外开放访问的 端口号 &#xff08;3&#xff09;测试&#xff1a;在 windows 系统中通过浏览器访…

交叉线和直通线各自用于什么场合?为什么?_【小麓讲堂】偏振光与LCD、OLED、3D、AR到底有什么关系?...

你了解自然界物体反射的光与电子显示设备发出的光有什么区别吗&#xff1f;你知道LCD、OLED、3D、AR的工作原理吗&#xff1f;你清楚偏振光与它们的关系吗&#xff1f;今天我们就跟大家聊一聊偏振光与多媒体显示设备的关系。人们常说眼睛是心灵的窗户&#xff0c;其实眼睛不单是…

php多个表中查找数据_Excel实战技巧74: 在工作表中创建搜索框来查找数据

学习Excel技术&#xff0c;关注微信公众号&#xff1a;excelperfect本文主要讲解如何创建一个外观漂亮的搜索框&#xff0c;通过它可以筛选数据并显示搜索结果。如下图1所示&#xff0c;在数据区域上方放置有一个文本框&#xff0c;用来输入要搜索的文本&#xff0c;其名称重命…

Nginx的配置实例(反向代理实例 )

目录 反向代理实例 1.实现效果 2.准备工作 &#xff08;1&#xff09;准备两个服务器&#xff0c;一个8080端口&#xff0c;一个 8081端口 &#xff08;2&#xff09;创建文件夹和测试页面 3.反向代理具体配置 &#xff08;1&#xff09;找到 nginx 配置文件&#xff0…

Spring框架概述(快速入门)

Spring 框架概述&#xff1a; 目录 Spring 框架概述&#xff1a; 1.Spring 是轻量级的开源的 javaEE 框架 2.Spring 有两个核心部分&#xff1a;IOC 和 AOP&#xff1a; 3.Spirng 特点&#xff1a; 4.Spring 的下载 5.接下来&#xff0c;通过一个小例子来掌握spring入门…

初学者怎么自学python编程_怎样自学python编程?从零开始学习python,400集免费教程!...

作为小白&#xff0c;在学习Python的时候&#xff0c;必然会走一定的弯路&#xff0c;有人在弯路上走丢了&#xff0c;有人走出了弯路。我就是属于还未走出弯路的同学&#xff0c;所以我想谈谈我的Python学习之路。 01先了解一下什么是python‍&#xff1f; Python 是一种通用的…

IOC容器(底层原理解读)

IOC的概念和原理 目录 IOC的概念和原理 1.什么是IOC &#xff08;1&#xff09;控制反转&#xff1a; &#xff08;2&#xff09;使用IOC的目的&#xff1a;降低耦合度 &#xff08;3&#xff09;IOC解耦过程图解 2.IOC的底层原理 3.IOC接口 &#xff08;1&#xff09…

python怎么画图片 wafer map_Python wafer_map包_程序模块 - PyPI - Python中文网

晶圆图 绘制一张晶圆图。用于半导体加工和分析。 内容安装 用法键盘快捷键和鼠标用法rel"nofollow">键盘快捷键和鼠标用法 注意事项当前能力 更改日志 功能鼠标和键盘快捷键&#xff01; 知道半M1-0302晶圆尺寸&#xff01; 你可以改变颜色&#xff01; 放大缩小&…

IOC操作Bean管理XML方式(创建对象和set注入属性)

目录 1.什么是 Bean 管理&#xff1a; &#xff08;1&#xff09;通过 Spring 创建对象 &#xff08;2&#xff09;通过 Spring 注入属性 2.IOC 操作 Bean 管理有两种方式&#xff1a; &#xff08;1&#xff09;基于 xml 配置文件方式实现 &#xff08;1.1&#xff09;基…