排序(三)——归并排序(MergeSort)

欢迎来到繁星的CSDN,本期内容主要包括归并排序(MergeSort)的实现

一、归并排序的主要思路

        归并排序和上一期讲的快速排序很像,都利用了分治的思想,将一整个数组拆成一个个小数组,排序完毕后进行再排序,直到整个数组排序完毕。

        唯一不同的是,归并排序是Out-place(需要额外空间),快速排序是In-place(不需要额外空间)。

        

        整体思路如下:

   1、单趟排序中,开辟一个等同于该数组大小的数组,并将其劈成两半。

   2、将两个子数组的元素从首元素开始进行比较(原因是递归会使得子数组已排序完毕,此时子数组的首元素一定为最小值。),然后将更小值塞入开辟的数组中。结束条件是某一个子数组全部塞完,此时将另一个数组的剩余元素全部追加到开辟数组的尾端即可。

   3、完成步骤二后,这两个子数组已排序完毕,将开辟数组的元素全部拷贝回这一轮的数组,返回,并开始上一级数组的再排序。

        所以主体代码如下:

void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}_MergeSort(a, tmp, 0, n - 1);free(tmp);tmp = NULL;
}

        其中_MergeSort函数为MergeSort函数的子函数(即单趟排序和递归)。

        tmp数组即我们开辟的额外数组。

   虽然可以频繁开辟数组并free,但多余的开辟操作无疑造成了操作上的繁杂,所以子函数中我们多了两个参数,就是为了定位到开辟的大数组中。

 二、归并排序的主体代码

void _MergeSort(int* a, int* tmp, int begin, int end)
{if (begin >= end)return;int mid = (begin + end) / 2;// 如果[begin, mid][mid+1, end]有序就可以进行归并了_MergeSort(a, tmp, begin, mid);_MergeSort(a, tmp, mid + 1, end);// 归并int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}
以上便是归并排序的主体代码,最后一行memcpy可以被替代为遍历赋值。整体代码思想和快排差别不大,只是开辟了额外空间,可以被理解为以空间换时间。

         归并排序的空间复杂度为O(n)(即开辟的数组),时间复杂度为O(nlogn),与快排一个量级,但没有快排那么需要小区间优化以及三数取中降低最坏情况的糟糕程度。

        

        1000000的量级,各大高效排序各显神威,都交出了一份极强的答卷。

        不过归并排序和希尔排序、堆排序、快速排序最大的区别就在于额外空间,属于典型的以空间换时间的做法。

        尽管如此,我们在实践中还是常用快速排序作为排序手段。

        饶是如此,归并排序的练习也可以帮助我们练习调试、增加递归的思路等等,具有较强的实际意义和练习价值。

三、归并排序的非递归版本

        和快速排序一样,归并排序作为一个递归版本的排序方式,一定有非递归版的来解决。

        首先还是找到归并排序为了什么而递归。

        _MergeSort这一子函数中,又再度引用了两个参数begin和end。

        不同于QuickSort用栈这一数据结构来解决问题,MergeSort必须从小到大排序,导致了用栈来模拟实现,无法得到数据的准确位置(因为每次QuickSort都能得到一个元素的最终位置)。

        换句话说,似乎只能像希尔排序一样,利用gap来解决问题了。

        代码如下:

void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}// gap每组归并数据的数据个数int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){// [begin1, end1][begin2, end2]int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;// 第二组都越界不存在,这一组就不需要归并if (begin2 >= n)break;// 第二的组begin2没越界,end2越界了,需要修正一下,继续归并if (end2 >= n)end2 = n - 1;int j = i;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));}gap *= 2;}free(tmp);tmp = NULL;
}

   gap的增长是以2为倍数的指数级增长,所以效率上没有拉下多少。同时将有关gap的部分去除,易发现剩余部分和_MergeSort这一子函数的内容没有多大差别。

        本篇内容到此结束,谢谢大家的观看!

        觉得写的还不错的可以点点关注,收藏和赞,一键三连。

        我们下期再见~

        往期栏目: 

排序(一)——冒泡排序、直接插入排序、希尔排序(BubbleSort,InsertSort,ShellSort)-CSDN博客

排序(二)——快速排序(QuickSort)-CSDN博客

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

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

相关文章

算法金 | 来了,pandas 2.0

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 今日 210/10000 Pandas 是一个强大的数据分析库&#xff0c;广泛应用于科学研究、金融分析、商业智能等领域。它提供了高效的数据结构…

PostgreSQL 中如何解决因长事务阻塞导致的其他事务等待问题?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中如何解决因长事务阻塞导致的其他事务等待问题&#xff1f;一、了解长事务阻塞的原因&…

Python - Word转TXT文本,或TXT文本转Word

Word文档&#xff08;.doc或.docx&#xff09;和纯文本文件&#xff08;.txt&#xff09;是两种常用的文件格式。Word文档通常用于复杂的文档处理和排版&#xff0c;而纯文本文件则用于存储和传输纯文本信息。了解如何在这两种格式之间进行转换能提高工作效率&#xff0c;并便于…

Matlab 判断直线上一点

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 判断一个点是否位于一直线上有很多方法,这里使用一种很有趣的坐标:Plucker线坐标,它的定义如下所示: 这个坐标有个很有趣的性质,我们可以使用Plucker坐标矢量构建一个Plucker矩阵: 则它与位于对应线上的齐次点…

Linux--USB驱动开发(二)插入USB后的内核执行程序

一、USB总线驱动程序的作用 a&#xff09;识别USB设备 1.1 分配地址 1.2 并告诉USB设备(set address) 1.3 发出命令获取描述符 b&#xff09;查找并安装对应的设备驱动程序 c&#xff09;提供USB读写函数 二、USB设备工作流程 由于内核自带了USB驱动,所以我们先插入一个U…

游戏如何应对黑灰产工作室

游戏黑灰产工作室&#xff0c;是指以非法渠道、非法手段通过游戏进行牟利的团伙。使用脚本、外挂是黑灰产工作室的显著特征&#xff0c;其常见的牟利方式有&#xff1a;打金工作室、资源囤积号、初始号、自抽号、代练工作室以及营销欺诈等。 ▲ 常见的游戏黑灰产工作室牟利路径…

从汇编层看64位程序运行——栈帧(Stack Frame)边界

大纲 RBP&#xff0c;RSP栈帧边界总结参考资料 在《从汇编层看64位程序运行——栈帧(Stack Frame)入门》中&#xff0c;我们简单介绍了栈帧的概念&#xff0c;以及它和函数调用之间的关系。如文中所述&#xff0c;栈帧是一种虚拟的概念&#xff0c;它表达了一个执行中的函数的栈…

CSS盒子模型 综合案例(产品布局模块)

&#xff08;期末周结束啦&#xff0c;暑假到来&#xff0c;又可以继续更新了呢&#xff01;&#x1f496;希望大家多多支持。大家好&#xff0c;时隔一段日子今天我们将继续来学习CSS的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&…

Python 使用 pip 安装 模块失败error: subprocess-exited-with-error 问题解决

今天安装了一个新版本的python&#xff0c;需要安装matplotlib包&#xff0c;死活安装不上&#xff0c;气死了&#xff0c;离线包都安装包不上&#xff0c;一直提示error: subprocess-exited-with-error。 翻看了很多资料&#xff0c;发现似乎是版本不匹配的原因&#xff0c;然…

十三、(正点原子)Linux自带的LED灯驱动

Linux 内核已经集成了像 LED 灯这样非常基础的设备驱动。Linux 内核的 LED 灯驱动采用platform 框架&#xff0c;因此我们只需要按照要求在设备树文件中添加相应的 LED 节点即可。 一、Linux内核自带LED驱动使能 要使用 Linux 内核自带的 LED 灯驱动首先得先配置 Linux 内核&a…

计算机网络之广域网

广域网特点: 主要提供面向通信的服务&#xff0c;支持用户使用计算机进行远距离的信息交换。 覆盖范围广,通信的距离远&#xff0c;需要考虑的因素增多&#xff0c; 线路的冗余、媒体带宽的利用和差错处理问题。 由电信部门或公司负责组建、管理和维护&#xff0c;并向全社会…

[ruby on rails]部署时候产生ActiveRecord::PreparedStatementCacheExpired错误的原因及解决方法

一、问题&#xff1a; 有时在 Postgres 上部署 Rails 应用程序时&#xff0c;可能会看到 ActiveRecord::PreparedStatementCacheExpired 错误。仅当在部署中运行迁移时才会发生这种情况。发生这种情况是因为 Rails 利用 Postgres 的缓存准备语句(PreparedStatementCache)功能来…

【UNI-APP】阿里NLS一句话听写typescript模块

阿里提供的demo代码都是javascript&#xff0c;自己捏个轮子。参考着自己写了一个阿里巴巴一句话听写Nls的typescript模块。VUE3的组合式API形式 startClient&#xff1a;开始听写&#xff0c;注意下一步要尽快开启识别和传数据&#xff0c;否则6秒后会关闭 startRecognition…

《基于 LatentFactor + Redis + ES 实现动态药房分配方法》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; 近期刚转战 CSDN&#xff0c;会严格把控文章质量&#xff0c;绝不滥竽充数&#xff0c;欢迎多多交流。&am…

从Centos7升级到Rocky linux 9后,网卡连接显示‘Wired connection 1‘问题解决方法

问题描述 从Centos7升级到Rocky9后, 发现网卡eth0的IP不正确。通过nmcli查看网卡连接&#xff0c;找不到name为eth0的连接&#xff0c;只显示’Wired connection 1’ 查看/etc/NetworkManager/system-connections/&#xff0c;发现找不到网卡配置文件。 原因分析 centos7使…

5G RedCap调查报告

一、5G RedCap技术背景 5G RedCap(Reduced Capability缩写,轻量化5G),是3GPP标准化组织定义下的5G裁剪版本,是5G面向中高速率连接场景的物联网技术,它的能力介于5G NR(含eMBB和uRLLC)和LPWA(如LTE-M和NR-IoT)之间,如图1所示,是5G-A(5G Advanced)的关键技术之一。…

PHP中的函数与调用:深入解析与应用

目录 一、函数基础 1.1 函数的概念 1.2 函数的定义 1.3 函数的调用 二、PHP函数的分类 2.1 内置函数 2.2 用户自定义函数 2.3 匿名函数 2.4 递归函数 2.5 回调函数 2.6 魔术方法 三、函数的参数与返回值 3.1 参数传递 3.2 返回值 四、函数的高级特性 4.1 可变函…

在linux中查找 / 目录下的以.jar结尾的文件(find / -name *.jar)

文章目录 1、查找 / 目录下的以.jar结尾的文件 1、查找 / 目录下的以.jar结尾的文件 [rootiZuf6332h890vozldoxcprZ ~]# find / -name *.jar /etc/java/java-1.8.0-openjdk/java-1.8.0-openjdk-1.8.0.342.b07-1.el9_0.x86_64/lib/security/policy/limited/US_export_policy.ja…

【BUG】Python3|COPY 指令合并 ts 文件为 mp4 文件时长不对(含三种可执行源代码和解决方法)

文章目录 前言源代码FFmpeg的安装1 下载2 安装 前言 参考&#xff1a; python 合并 ts 视频&#xff08;三种方法&#xff09;使用 FFmpeg 合并多个 ts 视频文件转为 mp4 格式 Windows 平台下&#xff0c;用 Python 合并 ts 文件为 mp4 文件常见的有三种方法&#xff1a; 调用…

设计模式8-桥模式

设计模式8-Bridge 桥模式 由来与目的模式定义结构桥接模式的结构结构说明 代码推导1. 类和接口的定义2. 平台实现3. 业务抽象4. 使用示例总结1. 类数量过多&#xff0c;复杂度高2. 代码重复3. 不符合单一职责原则4. 缺乏扩展性改进后的设计1. 抽象和实现分离&#xff08;桥接模…