受够了初级排序算法,今天来个效率高的——归并排序。

2023-11-11

受够了初级排序算法,今天来个效率高的——归并排序。

前情回顾:

在前几篇文章中我们学习了选择排序,插入排序,以及插入排序的优化版希尔排序,但是他们的时间复杂度都是O(N^2),现在我们终于迎来了我们算法效率大幅度提升的,时间复杂度为O(NlogN)算法——归并排序。

基本概念:

归并排序的具体含义就是合并两个有序的数组,使数组合并成为一个数组,并且合成的这一个数组整个内部都是有序的。当我们有了这个归并的算法之后,我们就可以用递归来把整个数组一分为二,二分为四,以此类推。最终我们会得到很小的数组。把这些小数组合并为有序的,最终我们就会得到整个有序的大数组。这也是分治方法的具体应用。

在这里插入图片描述

下面先讲一下归并的算法,首先开门见山,直接上代码。

public static void merge(int[] num,int[] temp,int lo, int mid, int hi){
    //其实并不是真正意义上的把数组分成两个,而是假想的,lo代表前面数组的第一个元素,mid代表前面数组的最后一个元素,hi表示后面数组的最后一个元素。    
    int i = lo;
        int j = mid+1;
        for (int k = lo; k <= hi; k++) {
            temp[k] = num[k];//temp是辅助数组。
        }
        for(int k = lo;k <= hi;k++){
            if(i > mid) num[k] = temp[j++];//如果前半部分数组空了以后,直接把后面的数组放入辅助数组。
            else if(j > hi) num[k] = temp[i++];//后半部分数组满了以后,直接把前面的数组放入辅助数组。
            else if(temp[i] < temp[j]) num[k] = temp[i++];//谁小谁放入辅助数组,然后相对应的指针加一。
            else num[k] = temp[j++];
        }
}

img

img

好了,到了现在我们已经有了最基本归并算法,下面我们就可以通过这个算法然后递归得到完整的归并排序算法。废话不多说,先上代码。

public class mergesort {
    public static void main(String[] args) {
        int[] num = {3,44,38,5,47,15,36,26,27,2,46,4,1,50,4832};//待处理的数组。
        mergeloop(num);
        System.out.println(Arrays.toString(num));

    }
    public static void sort(int[] num,int[] temp,int lo,int hi){
        if(lo>=hi)return;
        int mid = (lo+hi)/2;
        sort(num,temp,lo,mid);//mid代表前面数组中的最后一个元素,先把前半部分排好序。
        sort(num,temp,mid+1,hi);//在把后面部分排好序。
        merge(num,temp,lo,mid,hi);//然后将前面的部分和后面的部分归并排序,行成一个完整的有序的大数组。
    }
    public static void sort(int[] num){
        //这个函数创建的意义就是一次性把辅助数组给创建出来,而不是放入上面的递归的函数中,那样大部分时间就会花在来回创建数组上,会导致算法的效率大幅度降低。
        int[] temp = new int[num.length];
        sort(num,temp,0,num.length-1);
    }
    public static void merge(int[] num,int[] temp,int lo, int mid, int hi){
        int i = lo;
        int j = mid+1;
        for (int k = lo; k <=hi; k++) {
            temp[k] = num[k];
        }
        for(int k = lo;k <= hi;k++){
            if(i > mid) num[k] = temp[j++];
            else if(j>hi) num[k] = temp[i++];
            else if(temp[i] < temp[j]) num[k] = temp[i++];
            else num[k] = temp[j++];
        }
    }
}

其实这个递归算法并不难想,也很好理解,但考虑到我博客的全面性,我还是简要的用递归的概念解释一下代码。

**递归调用的函数会不断的压栈,然后等到lo>=hi,然后函数进行出栈。**然后我写出函数的调用轨迹你们就理解上面的整个调用过程了。

归并排序算法调用过程:

sort(num,0,15)//前半部分
	sort(num,0,7)
		sort(num,0,3)
			sort(num,0,1)
				merge(num,0,0,1)
			sort(num,2,3)
				merge(num,2,2,3)
			merge(num,0,1,3)
		sort(num,4,7)
			sort(num,4,5)
				merge(num,4,4,5)
			sort(num,6,7)
				merge(num,6,6,7)
			merge(num,4,5,7)
		merge(num,0,3,7)
	sort(num,8,15)//后半部分
		sort(num,8,11)
			sort(num,8,9)
				merge(num,8,8,9)
			sort(num,10,11)
				merge(num,10,10,11)
			merge(num,8,9,11)
		sort(num,12,15)
			sort(num,12,13)
				merge(num,12,12,13)
			sort(num,14,15)
				merge(num,14,14,15)
			merge(num,12,13,15)
		merge(num,8,11,15)
	merge(num,0,7,15)归并结果。

以上就是归并排序的整个调用过程了,相信现在大家都已经懂了吧。

众所周知,一般来说能用递归实现的问题都能用for循环来实现,下面我们就写出用for循环来演示归并排序的算法。废话不多说,先上代码。

 public static void mergeloop(int[ ] num){
        int N = num.length;
        int[] temp = new int[num.length];
        for(int sz = 1;sz <= N;sz = sz+sz){//sz表示数组的大小。我们把一个元素假定为一个数组。sz为1,2,4,8,16.
            for(int lo = 0;lo < N-sz;lo+=sz+sz){lo表示假想的前面那个数组的头部索引。
                merge(num,temp,lo,lo+sz-1,Math.min(lo+sz+sz-1,N-1));
                //lo+sz-1表示前面那个数组的末尾,就相当于上面的mid。
                //后面之所以用Math.min(lo+sz+sz-1,N-1),是因为到最后的时候数组不一定对称。找到最小的。
            }
        }
    }

循环归并的调用过程:

sz=1:
	merge(num,0,0,1)
	merge(num,2,2,3)
	merge(num,4,4,5)
	merge(num,6,6,7)
	merge(num,8,8,9)
	merge(num,10,10,11)
	merge(num,12,12,13)
	merge(num,14,14,15)
sz=2:
	merge(num,0,1,3)
	merge(num,4,5,7)
	merge(num,8,9,11)
	merge(num,12,13,15)
sz=4:
	merge(num,0,3,7)
	merge(num,8,11,15)
sz=8:
	merge(num,0,7,15)

好了,到现在我们已经把归并排序的递归版和归并排序的循环版都讲完了,并且已经把整个函数的调用过程都写了出来,这样一来就没有什么不懂得了吧。归并排序的排序效率已经比较之前的算法效率已经大幅度提升了。下面我们就会讲快速排序了。

本人良弓,初来乍到,请多关照。~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

受够了初级排序算法,今天来个效率高的——归并排序。 的相关文章

  • 上传进度条 Java Servlet?

    我想使用 servlet 显示上传进度条 我尝试过Ajax iFrame 技术 页面没有重新加载 文件也被上传 但是 进度条没有出现 有没有可用于 javaservlts 的 jQuery 进度插件 Thanks 我强烈推荐jQuery 上
  • 在Windows Server 2003下如何在本地系统帐户下运行jvisualvm.exe?

    我在带有 Java 1 6 u 20 的 Windows Server 2003 下将 GlassFish 3 0 1 作为 Windows 服务运行 总体上我很满意 我希望能够在这个 JVM 上使用 VisualVM 并使用无法在 Tom
  • java程序有多少种结束方式?

    我知道使用 System exit 0 可以结束一个java程序 例如 如果我有一个JFrame窗口 它会关闭并结束程序 但我想知道还有多少其他方法 可以关闭它并结束程序 包括发生错误时 程序会被关闭 JFrame也会被关闭吗 添加到其他答
  • Kafka - 如何同时使用过滤器和过滤器?

    我有一个 Kafka 流 它从一个主题获取数据 并且需要将该信息过滤到两个不同的主题 KStream
  • Java 中的 <-- 是什么? [复制]

    这个问题在这里已经有答案了 我遇到了下面的片段 它输出到4 3 2 1 我从来没有遇到过 lt 在爪哇 Is lt 使 var1 的值变为 var2 的运算符 public class Test public static void mai
  • 我们可以有条件地声明 spring bean 吗?

    有没有一种方法可以有条件地声明 Spring bean 例如
  • 有人用过 ServiceLoader 和 Guice 一起使用吗?

    我一直想通过我们的应用程序 构建系统进行更大规模的尝试 但更高的优先级不断将其推到次要地位 这似乎是加载 Guice 模块的好方法 并且避免了关于 硬编码配置 的常见抱怨 单个配置属性很少会自行更改 但您几乎总是会有一组配置文件 通常用于不
  • 无法使用 datastax java 驱动程序通过 UDT 密钥从 cassandra 检索

    我正在尝试使用用户定义的类型作为分区键将对象存储在 cassandra 中 我正在使用 datastax java 驱动程序进行对象映射 虽然我能够插入到数据库中 但无法检索该对象 如果我更改分区键以使用非 udt 例如文本 我就能够保存和
  • 自定义列表字段点击事件

    我正在编写一个应用程序 其中我创建了用于显示列表视图的自定义列表字段 我的 CustomListField 包含连续的一个图像和文本 我正在通过单击列表字段行获取字段更改侦听器 但我也想将字段更改侦听器放在图像上 谁能告诉我我该怎么做 这是
  • 为什么用scala写的代码比用java写的慢6倍?

    我不确定我在编写 scala 代码时是否犯了一些错误 问题是 The four adjacent digits in the 1000 digit number that have the greatest product are 9 9
  • JAXB - 忽略元素

    有什么方法可以忽略 Jaxb 解析中的元素吗 我有一个很大的 XML 文件 如果我可以忽略其中一个大而复杂的元素 那么它的解析速度可能会快很多 如果它根本无法验证元素内容并解析文档的其余部分 即使该元素不正确 那就更好了 例如 这应该只生成
  • 在java程序中使用c++ Dll

    我正在尝试使用System LoadLibrary 使用我用 C 编写的一个简单的 dll UseDllInJava java import com sun jna Library import com sun jna Native imp
  • Android - 存储对ApplicationContext的引用

    我有一个静态 Preferences 类 其中包含一些应用程序首选项和类似的内容 可以在那里存储对 ApplicationContext 的引用吗 我需要该引用 以便我可以在不继承 Activity 的类中获取缓存文件夹和类似内容 你使用的
  • Tomcat 6 未从 WEB-INF/lib 加载 jar

    我正在尝试找出我的 tomcat 环境中的配置问题 我们的生产服务器正在运行 tomcat 安装并从共享 NFS 挂载读取战争 然而 当我尝试使用独立的盒子 及其配置 进行同样的战争时 我收到下面发布的错误 有趣的是 如果我将 WEB IN
  • 我所有的 java 应用程序现在都会抛出 java.awt.headlessException

    所以几天前我有几个工作Java应用程序使用Swing图书馆 JFrame尤其 他们都工作得很好 现在他们都抛出了这个异常 java awt headlessexception 我不知道是什么改变了也许我的Java版本不小心更新了 谢谢你尽你
  • 使用 Apache 允许 Glassfish 和 PHP 在同一服务器中协同工作

    是否可以建立从 Java 到 php 文件的桥梁 我有一个用 Java 编写的应用程序 我需要执行http piwik org http piwik org 这是用 PHP 编写的 在服务器中 我正在运行 PHP 但无法从浏览器访问 php
  • Android ScrollView,检查当前是否滚动

    有没有办法检查标准 ScrollView 当前是否正在滚动 方向是向上还是向下并不重要 我只需要检查它当前是否正在滚动 ScrollView当前形式不提供用于检测滚动事件的回调 有两种解决方法可用 1 Use a ListView并实施On
  • Selenium 单击在 Internet Explorer 11 上不起作用

    我尝试在 Internet Explorer 上单击 selenium 但它不起作用 我努力了element click moveToElement element click build perform javascript没事了 事实上
  • 检测到 JVM 正在关闭

    我有一个使用 addShutdownHook 处理 Ctrl C 的 Swing 应用程序 它工作正常 直到我的关闭任务之一调用一个在正常情况下更改 JLabel 文本的函数 此时它挂起 我认为问题是 Swing EDT 已终止或正在等待某
  • 设置 TreeSet 的大小

    有没有办法像数组一样对 Java 集合中的 TreeSet 进行大小限制 例如我们在数组中 anArray new int 10 数组具有固定长度 在创建数组时必须指定该长度 A TreeSet当您向其中添加元素时会自动增长 您无法设置其大

随机推荐

  • UI控件----ProgressBar进度条 实例总结

    ProgressBar提供了可以向用户展示当前任务的进度 完成效果如下 单击增加 减少进度可以调节进度 完成步骤一 layout的xml文件中activity main xml完成代码
  • LRU的实现

    题目内容 实现一个 LRUCache 类 三个接口 LRUCache int capacity 创建一个大小为 capacity 的缓存 get int key 从缓存中获取键为 key 的键值对的 value put int key in
  • 使用Elasticsearch 出现的拒绝连接

    pom 文件 spring elasticsearch jest uris http 192 168 124 142 9201 data elasticsearch cluster name elasticsearch cluster no
  • 应用向国产架构体系化迁移的三大难点及解决方案

    转载本文需注明出处 微信公众号EAWorld 违者必究 李航 国家信创战略背景下 信创产业从党政 金融等领域高速扩展到电信 制造 教育等更广阔的市场 01 信创工作要解决应用向国产架构体系化迁移的三大难点 保障全面落地 伴随近年来信创实践的
  • pandas.errors.ParserError: Error tokenizing data. C error: Expected 17 fields in line 112, saw 18

    pandas errors ParserError Error tokenizing data C error Expected 17 fields in line 112 saw 18 pandas 简介 pandas 读取csv文件 运
  • 数字化时代,如何从战略设计到架构来打造智慧银行?

    导语 随着人工智能 大数据 云计算等技术向纵深发展 数字化转型已成为银行发展的 必答题 调整战略规划和架构重组 加大信息科技投入 推进科技人才队伍建设 持续推出数字化产品 近年来 深化数字化转型 以科技赋能金融服务已成为不少银行的发力点 今
  • python环境变量配置

    python现在的版本 主要是python2和python3两个大版本 这两个版本有很大的不同 当我们在自己电脑上同时安装了python2 x和python3 x版本的解释器的时候 就需要对环境变量的配置进行一定的修改 大概解释一下 我对环
  • 什么是 前端&后端,始端&末端

    前端 后端 前端和后端是指不同的开发领域和技术 前端指的是用户可见的界面 比如网页 移动应用 游戏等 使用的技术包括HTML CSS JavaScript等 后端指的是用户看不见的部分 比如服务器 数据库 业务逻辑等 使用的技术包括Java
  • 数据结构笔记--图

    数据结构笔记 图 图 本章总结 图的概念 基本术语 抽象数据类型 图的存储结构 邻接矩阵表示法 数组 无向图 有向图 有权图 邻接矩阵的优缺点 代码实现 邻接表表示法 链式 结构 无向图 有向图 邻接表的优缺点 邻接矩阵与邻接表的对比 代码
  • 详解spring的IOC控制反转和DI依赖注入

    转载 详解spring的IOC控制反转和DI依赖注入 2018 06 05 15 45 34 jiuqijack 阅读数 2945 文章标签 spring IOC控制反转 DI依赖注入 更多 分类专栏 spring
  • 关于Android的不同分辨率图片适配

    看了几篇相关的博客 根据自己的实际开发 总结了一下 首先要搞清楚 图片的分辨率单位是像素 也就是px 比如72x72的图片 就是长宽都是72px 手机屏幕的分辨率跟图片类似 但是它还有个很重要的指标 dpi 叫做像素密度 代表1英寸长度的屏
  • 【C++】C++11 STL算法(三):分隔操作(Partitioning operations)、排序操作(Sorting operations)

    目录 分隔操作 Partitioning operations 一 is partitioned 1 原型 2 说明 3 官网demo 二 partition 1 原型 2 说明 3 官方demo 三 partition copy 1 原型
  • Spring MVC静态资源映射

    Spring MVC静态资源映射 静态资源映射 使用容器的默认Servlet location mapping cache period order Spring MVC需要对RESTful风格的URL提供支持 而真正的RESTful风格的
  • C++11中std::thread线程实现暂停(挂起)功能

    一 封装Thread类 我们基于C 11中与平台无关的线程类std thread 封装Thread类 并提供start stop pause resume 线程控制方法 为了让线程在暂停期间 处于休眠 不消耗CPU 我们使用C 11提供的锁
  • Amazon Gamelift游戏托管服务

    Amazon GameLift是亚马逊云科技推出的一种用于托管专用游戏服务器的托管服务 它可以安全地预置实例 在正在运行的实例上部署游戏服务器 在游戏服务器队列间对流量进行负载均衡 监控实例和游戏服务器的运行状况 并在无需人工干预的情况下替
  • jaffe 数据库百度网盘下载

    供学术研究讨论使用 禁止商用 如有引用请注明jaffe论文出处 链接 https pan baidu com s 1Rc18GnVqP7WRmayFAhrtYA 提取码 2jq8
  • 前端常用的几种加密方法

    目前在前端开发中基本都会用到加密 最常见的就是登录密码的加密 接下来会为大家介绍几种加密方法 md5 加密 MD5 加密后的位数有两种 16 位与 32 位 默认使用32位 16 位实际上是从 32 位字符串中取中间的第 9 位到第 24
  • 《C和C++安全编码》读书笔记(一)

    第一章 夹缝求生 1 1 衡量危险 生产不安全软件系统的风险可以从历史风险和潜在的未来风险两方面进行评估 威胁的来源 黑客 内部人员 罪犯 竞争情报从业者 恐怖分子 信息战士 CERT CC 美国计算机紧急事件响应小组协调中心 监控漏洞信息
  • 图解通信原理与案例分析-21:4G LTE多天线技术--天线端口、码流、分集Diveristy、波束赋形BF、空分复用MIMO、空分多址

    目录 前言 第1章 MIMO多天线技术概述 1 1 三大目的 1 2 六大分类 第2章 单天线SISO 单输入单输出 2 1 概述 2 2 实现原理 多路 异频 发送 接收 对 第3章 接收分集MISO 多输入单输出 冗余接收 3 1 概述
  • 受够了初级排序算法,今天来个效率高的——归并排序。

    受够了初级排序算法 今天来个效率高的 归并排序 前情回顾 在前几篇文章中我们学习了选择排序 插入排序 以及插入排序的优化版希尔排序 但是他们的时间复杂度都是O N 2 现在我们终于迎来了我们算法效率大幅度提升的 时间复杂度为O NlogN