归并排序的具体实现过程

作者主页:paper jie的博客_CSDN博客-C语言,算法详解领域博主

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《算法详解》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将算法基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《系统解析C语言》《C语言》《C语言-语法篇》

内容分享:本期将对八大排序中的希尔排序进行详细的讲解,各位看官姥爷快搬好小板凳坐好叭。

    -------- 不要998,不要98,只要一键三连,三连买不了吃亏,买不了上当

前言

上期我们介绍了选择排序的改进版—堆排序,具体分析了它的基本思想,代码的实现和算法复杂度,这期我们将讲解八大排序的最后一个—归并排序。

什么是归并排序

百度百科中说归并算法就是把序列递归划分成为一个个短序列,以其中只有1个元素的直接序列或者只有2个元素的序列作为短序列的递归出口,再将全部有序的短序列按照一定的规则进行排序为长序列。归并排序融合了分治策略,即将含有n个记录的初始序列中的每个记录均视为长度为1的子序列,再将这n个子序列两两合并得到n/2个长度为2(当凡为奇数时会出现长度为l的情况)的有序子序列;将上述步骤重复操作,直至得到1个长度为n的有序长序列。需要注意的是,在进行元素比较和交换时,若两个元素大小相等则不必刻意交换位置,因此该算法不会破坏序列的稳定性,即归并排序也是稳定的排序算法。

我自己的理解就是归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并排序的实现

基本思想

1 把序列分成元素个数尽量相等的两半。 
2 把两半元素分别进行归并排序。
3 把两个有序数组合并成一个。

具体代码

#include <stdio.h>
int merge(int r[],int s[],int x1,int x2,int x3)    //自定义实现一次归并样序的函数
{int i,j,k;i=x1;    //第一部分的开始位置j=x2+1;  //第二部分的开始位置k=x1;while((i<=x2)&&(j<=x3))    //当i和j都在两个要合并的部分中时if(r[i]<=r[j])    //筛选两部分中较小的元素放到数组s中{s[k] = r[i];i++;k++;}else{s[k]=r[j];j++;k++;}while(i<=x2)    //将x1〜x2范围内未比较的数顺次加到数组r中s[k++]=r[i++];while(j<=x3) //将x2+l〜x3范围内未比较的数顺次加到数组r中s[k++]=r[j++];return 0;
}
int merge_sort(int r[],int s[],int m,int n)
{int p;int t[20];if(m==n)s[m]=r[m];else{p=(m+n)/2;merge_sort(r,t,m,p);    //递归调用merge_soit()函数将r[m]〜r[p]归并成有序的t[m]〜t[p]merge_sort(r,t,p+1,n);    //递归一调用merge_sort()函数将r[p+l]〜r[n]归并成有序的t[p+l]〜t[n]merge(t,s,m,p,n);    //调用函数将前两部分归并到s[m]〜s[n】*/}return 0;
}
int main()
{int a[11];int i;printf("请输入10个数:\n");for(i=1;i<=10;i++)scanf("%d",&a[i]);    //从键盘中输入10个数merge_sort(a,a,1,10);    //调用merge_sort()函数进行归并排序printf("排序后的顺序是:\n");for(i=1;i<=10;i++)printf("%5d",a[i]);    //输出排序后的数据printf("\n");return 0;
}

归并排序的实现原理

递归:调用自身 分治:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。比喻10只筷子不好折,分成5和5,5还不好折,再分成2和3,还觉得不好折,再分成1和1(1和2)。像这样将大问题分成一样类型的小问题,在各个击破。归并排序实现思路:把数组从中间分开(分为左,右俩部分),左边再次从中间分开分成俩部分,右边再次从中间分开分成俩部分,一直这样分下去,直到不能再分。从最底层开始一直向上有序的合并。最终完成排序。

假设我们希望从小到大排序。合并的过程主要是在两个序列的起点各设置一个指针。因为两个序列已经是分别有序的了,那我们每次只需要把两个序列中最小的元素加以比较,将其中比较小的元素加入到临时数组,然后将该指针向后移动,直到其中一个序列的指针走完整个序列为止。接着需要把另一个序列可能剩下的值都加到排序之后的序列的末尾。最后将临时数组的元素值赋值回原始数组。

这里有一点需要考虑的是,当两个序列当前指针对应的元素相等时,应该移动哪一个?虽然说移动哪一个指针都可以,但是我们一般会移动第一个序列的指针。因为这样可以保持排序的稳定性。即保持序列中相同值在排序之后顺序不变。

归并排序的难点是如何合并,实际上这是比较好理解的,但是需要写更多的代码,因为需要考虑序列为空以及把临时序列的值存回原序列的情况。快速排序的难点是如何划分,这个问题我认为相对归并的难点是比较难理解的。

另一点需要注意的是,快排是先划分过程,然后递归。归并是先递归,然后合并。看上去相反的但是实际是由于两个排序的步骤有些是不需要做任何操作的。

复杂度

空间复杂度

递归代码的空间复杂度并不能像时间复杂度那样累加。尽管每次合并操作都需要申请额外的内存空间,但在合并完成之后,临时开辟的内存空间就被释放掉了。在任意时刻,CPU 只会有一个函数在执行,也就只会有一个临时的内存空间在使用。临时内存空间最大也不会超过 n 个元素的大小,所以归并排序的空间复杂度是 O(n)。

时间复杂度

归并排序的递归树,树种每层元元素的个数最多是n,也就代表着每层最多进行n次比较,而递归树最多只有log2n层,合在一起就是nlog2n了。


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

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

相关文章

【JavaEE初阶】CSS

摄影分享~ 文章目录 一.CSS基本规范1. CSS基本语法规范2.CSS选择器 二.CSS常用属性1. 字体属性2.文本属性3.背景属性4.圆角矩形5.元素的显示模式块级元素行内元素 6.盒子模型边框内边距外边距 7.弹性布局 一.CSS基本规范 层叠样式表。(Cascading Style Sheets) CSS 能够对网页…

【深度学习】AIGC ,ControlNet 论文,原理,训练,部署,实战,教程

论文&#xff1a;https://arxiv.53yu.com/pdf/2302.05543 代码&#xff1a;https://github.com/lllyasviel/ControlNet 得分几个博客完成这个事情的记录了&#xff0c;此篇是第一篇&#xff0c;摘录了一些论文内容。ControlNet 的原理极为朴实无华&#xff08;对每个block添加…

BPMNJS 在HTML中的引入与使用

BPMNJS 在HTML中的引入与使用 在网上看到的大多是基于vue使用BPMN的示例或者教程&#xff0c;竟然没有在HTML使用的示例&#xff0c;有也是很简单的介绍核心库的引入和使用&#xff0c;并没有涉及到扩展库。于是简单看了下&#xff0c;真的是一波三折&#xff0c;坎坎坷坷。不过…

【UE5 Cesium】08-Cesium for Unreal 子关卡应用实例(上)

UE版本&#xff1a;5.1 效果 &#xff08;运行游戏可以看到进入关卡体积内楼房模型才会显现&#xff0c;以此来减少电脑性能消耗&#xff09; 步骤 一、新建两个子关卡&#xff08;以北京和上海为例&#xff09; 点击窗口-》关卡-》新建 命名第一个子关卡为“SubLevel_Bei…

【数据库】使用DBever连接人大金仓数据库

下载安装DBever 首先需要下载并安装DBever&#xff0c;可以在DBever官网上下载最新版的安装程序&#xff0c;根据提示进行安装即可。 下载驱动程序 首先需要从人大金仓官方网站下载适用于DBever的驱动程序。下载完成后&#xff0c;将驱动程序保存到本地计算机上。 添加驱动…

7.4.2 【Linux】特殊设备 loop 挂载 (镜像文件不烧录就挂载使用)

挂载光盘/DVD镜像文件 如此一来我们不需要将这个文件烧录成为光盘或者是 DVD 就能够读取内部的数据了。 创建大文件以制作 loop 设备文件&#xff01; 创建大型文件 假设我要创建一个空的文件在 /srv/loopdev &#xff0c;那可以这样做&#xff1a; 将 512 块&#xff0c;每…

【算法|动态规划系列No.5】leetcode62. 不同路径

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

linux内核TCP源码浅析

目录 数据接收流程驱动层网络层ip_local_deliverip_local_deliver_finish 传输层tcp_v4_rcvtcp_v4_do_rcvtcp_rcv_establishedtcp_recvmsg linux内核源码下载&#xff1a;https://cdn.kernel.org/pub/linux/kernel/ 我下载的是&#xff1a;linux-5.11.1.tar.gz 数据接收流程 …

window.open()实现PDF预览

效果图如下&#xff1a; 页面使用: window.open(strUrl) 参数说明如下图:

Android Studio中配置aliyun maven库

Android Studio中配置aliyun maven库 在项目的根build.gradle里面&#xff08;不是module&#xff09;buildscriptde对应位置添加配置&#xff1a; buildscript {repositories {maven {url http://maven.aliyun.com/nexus/content/groups/public/allowInsecureProtocol true…

ubuntu下 C/C++程序读取设置环境变量

设置环境变量很简单比如&#xff1a; export QMCY_LOCAL_PORT8888 追加的话 export QMCY_LOCAL_PORT$QMCY_LOCAL_PORT:8000 可以通过echo回显 读取的话 main函数多加一个env参数 一个字符串数组 然后遍历这个数组 即可 使用的时候 如下&#xff1a; bool QMCY_APP::Init(s…

Redis详细

Redis简介 Redis的数据类型 Redis中的常用指令 通用指令 字符串操作指令 set num 1 get num setex num1 10 1 get num1 incr num incrby num 3 decr num decrby num 3哈希操作命令 列表&#xff08;List&#xff09;操作命令 rpoplpush source dest 将source中的末尾元素移除…