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

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 GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • 如何在 Play java 中创建数据库线程池并使用该池进行数据库查询

    我目前正在使用 play java 并使用默认线程池进行数据库查询 但了解使用数据库线程池进行数据库查询可以使我的系统更加高效 目前我的代码是 import play libs Akka import scala concurrent Ex
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 我可以使用 HSQLDB 进行 junit 测试克隆 mySQL 数据库吗

    我正在开发一个 spring webflow 项目 我想我可以使用 HSQLDB 而不是 mysql 进行 junit 测试吗 如何将我的 mysql 数据库克隆到 HSQLDB 如果您使用 spring 3 1 或更高版本 您可以使用 s
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • AWS 无法从 START_OBJECT 中反序列化 java.lang.String 实例

    我创建了一个 Lambda 函数 我想在 API 网关的帮助下通过 URL 访问它 我已经把一切都设置好了 我还创建了一个application jsonAPI Gateway 中的正文映射模板如下所示 input input params
  • Eclipse Java 远程调试器通过 VPN 速度极慢

    我有时被迫离开办公室工作 这意味着我需要通过 VPN 进入我的实验室 我注意到在这种情况下使用 Eclipse 进行远程调试速度非常慢 速度慢到调试器需要 5 7 分钟才能连接到远程 jvm 连接后 每次单步执行断点 行可能需要 20 30
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 当我从 Netbeans 创建 Derby 数据库时,它存储在哪里?

    当我从 netbeans 创建 Derby 数据库时 它存储在哪里 如何将它与项目的其余部分合并到一个文件夹中 右键单击Databases gt JavaDB in the Service查看并选择Properties This will
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j

随机推荐

  • 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