一起学数据结构(12)——归并排序的实现

news2024/11/18 15:47:07

1. 归并排序原理:

归并排序的大概原理如下图所示:

        从图中可以看出,归并排序的整体思路就是把已给数组不断分成左右两个区间,当这个区间中的数据数量到达一定数值时,便返回去进行排序,整体的结构类似二叉树的结构,因此,对于归并排序同样可以利用递归进行实现。

       对于递归实现归并排序,首先需要实现的第一步便是如何区分左右区间,在快速排序中,虽然在递归时依然同样需要根据一个值来区分左右区间,但是用于区分左右区间的值是在左右两边遍历数组时自动选出来的,对于归并排序,通过观察可以发现,归并排序的左右区间是通过数组下标的中间值进行区分的,为了方便表示,将这个中间值命名为mid,例如,数组在进行第一次区分左右区间时,左区间的范围是[0,3],右区间的范围是[4,7]通过计算不难得到mid = 3,所以,对于数组左右区间的划分,可以通过midbegin(数组下标起始),end(数组下标末位来划分)即

                                                          左区间范围:[0,mid]

                                                          右区间范围:[mid+1,end]

       同时,在图中当区间中的数值数量为2后,下一步直接进行排序,此处图中省略了区间分为两个区间数值数量为1的两个区间的过程,这是因为,在区间中的数值数量< 2时,便停止划分区间

所以,对于区间划分这部分的递归,可以用代码表示为:

 //归并排序
 void _MergeSort(int* a, int begin, int end)
 {
	 if (begin >= end)
	 {
		 return;
	 }

	 int mid = (begin + end) / 2;

	 MergeSort(a, begin, mid);
	 MergeSort(a,mid + 1, end);
 }

在区间划分结束后,就需要对数组进行排序。这里需要注意,在进行排序时,不能直接在原本已有的数组进行排序,为了解决这个问题,本文选择独立开辟一块空间用于排序,当一部分区间在这部分空间排序完成后,便将这部分内容返回到原数组,开辟空间的过程如下:

 void MergeSort(int* a, int begin, int end)
 {
	 int* tmp = (int*)malloc(sizeof(int) * (end - begin + 1));
	 if (tmp == NULL)
	 {
		 perror("malloc fail");

	 }
	 _MergeSort(a, tmp, begin, end);
 }

因为开辟的空间需要在上面的函数中使用,所以对于函数的定义需要更改为上图中的格式。

对于如何排序,文章给出下面的方法:

对于一个区间,定义四个变量,分别为:begin1,end1,begin2,end2,具体使用方法如下:

begin1 = begin,end1 = mid,begin2 = mid+1,end2 = end,具体使用方法如下方的代码所示:

 //归并排序
 void _MergeSort(int* a,int* tmp, int begin, int end)
 {
	 if (begin >= end)
	 {
		 return;
	 }

	 int mid = (begin + end) / 2;

	 _MergeSort(a,tmp, begin, mid);
	 _MergeSort(a,tmp,mid + 1, end);

	 int begin1 = begin, end1 = mid;
	 int begin2 = mid + 1, end2 = end;
	 int index = begin;
	 while (begin1 <= end1 && begin2 <= end2)
	 {
		 if (a[begin1] < a[begin2])
		 {
			 tmp[index++] = a[begin1++];
		 }
		 else
		 {
			 tmp[index++] = a[begin2++];
		 }
	 }
	 while (begin1 <= end1)
	 {
		 tmp[index++] = a[begin1++];
	 }
	 while (begin2 <= end2)
	 {
		 tmp[index++] = a[begin2++];
	 }
	 memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
 }

为了方便解释代码内容,给出下面的图像:

 首先对左右区间进行区分,期间各个区间的begin1,end1,begin2,end2,如图所示,当区间数据数量< 2时,停止区分区间进行排序,例如对[10,6]这个区间,如果a[begin1] < a[begin2],则让小的哪个值插入到tmp,此时tmp中的内容如下图所示:

向原数组拷贝数值后,原数组左区间数值如下:

[10,6]区间遍历完成后,再遍历[7,1]区间,由于begin 的不同,再数据调整完拷贝到tmp后,tmp数组内容为:

 

随后再向原数组中拷贝,原数组内容为

 

对于其他的序列,依旧按照此规律,此部分不再叙述。

测试函数如下:
 

void TestMergeSort()
{
	int i[] = { 10,6,7,1,3,9,4,2 };
	int size = sizeof(i) / sizeof(int);
	MergeSort(i, 0, size - 1);
	printf("归并排序:");
	ArrayPrint(i, size);
}

运行结果如下:

 

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

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

相关文章

【Master公式】对于这一类符合的递归可以直接确定时间复杂度

Master公式 T(N) a T(N/b) O(N^d) 对于这一类符合的递归可以直接确定时间复杂度 a,b,c为常数 1、子问题调用了a次 2、子问题的规模一致&#xff0c;N/b指每个子问题处理总规模/b个规模&#xff08;只看规模&#xff0c;常数个忽略&#xff0c;如L,mid,mid1,R&#xff09; 3、…

【Airflow】构建爬虫任务系统

爬虫脚本太多了需要进行管理一下&#xff0c;领导决定使用airflow 我了解了一下这个平台是用来做任务调度。 是一个ETL工具 ETL是将业务系统的数据经过抽取、清洗转换之后加载到数据仓库的过程 这里是一个github的地址 https://github.com/apache/airflow 这里是官方文档 http…

手机桌面待办事项APP推荐

每天&#xff0c;我们每个人都面临着繁琐的事务和任务&#xff0c;而手机成了我们日常生活中不可或缺的伙伴。手机上的待办事项工具像一个可靠的助手&#xff0c;可以帮助我们更好地记录、管理和完成任务。在手机桌面上使用的待办事项APP推荐用哪一个呢&#xff1f; 手机是我们…

【QT】信号和槽

一、前置示例代码 main.cpp #include "widget.h"#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv); // 应用程序对象a&#xff0c;在Qt中&#xff0c;应用程序对象&#xff0c;有且仅有一个。Widget w; // 窗口对…

python sqlalchemy(ORM)- 02 表关系

文章目录 表关系ORM表示 1v1ORM表示 1vm 表关系 1:1&#xff0c;表A 中的一条记录&#xff0c;仅对应表B中的一条记录&#xff1b;表B的一条记录&#xff0c;仅对应表A的一条记录。1:m&#xff0c;表A中的一条记录&#xff0c;对应表B中的多条记录&#xff0c;表B中的一条记录…

编译原理-词法分析器

文章目录 对于词法分析器的要求概念词法分析器的功能和输出形式 词法分析器的设计词法分析器的结构单词符号的识别&#xff1a;超前搜索状态转换图 正规表达式和有限自动机正规式和正规集确定有限自动机&#xff08;DFA&#xff09;非确定有限自动机&#xff08;NFA&#xff09…

多级缓存入门

文章目录 什么是多级缓存JVM进程缓存环境准备安装MySQL导入Demo工程导入商品查询页面 初识Caffeine Lua语法初识Lua第一个lua程序变量和循环Lua的数据类型声明变量循环 条件控制、函数函数条件控制 多级缓存安装OpenRestyOpenResty快速入门反向代理流程OpenResty监听请求编写it…

scrapy的安装和使用

一、scrapy是什么&#xff1a;Scrapy是一个为了爬取网站数据&#xff0c;提取结构性数据而编写的应用框架&#xff0c;可以应用在包括数据挖掘&#xff0c;信息处理或存储历史数据等一系列的程序 二、scrapy的安装&#xff1a;pip install scrapy -i https://pypi.douban.com/…

CURL简单使用

前言 最近做项目&#xff0c;需要服务器实现网络是否通畅&#xff0c;比如通过健康检查接口&#xff0c;但是只能linux服务器测试&#xff0c;很可能还需要测试h2&#xff0c;所以想到了curl&#xff0c;整理一版简单用法。 curl 实际上curl是有官网的&#xff0c;只不过比较…

java中的异常,以及出现异常后的处理【try,catch,finally】

一、异常概念 异常 &#xff1a;指的是程序在执行过程中&#xff0c;出现的非正常的情况&#xff0c;最终会导致JVM的非正常停止。 注意: 在Java等面向对象的编程语言中&#xff0c;异常本身是一个类&#xff0c;产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的…

C语言-面试题实现有序序列合并

要求&#xff1a; a.输入两个升序排列的序列&#xff0c;将两个序列合并为一个有序序列并输出。 数据范围&#xff1a; 1≤n,m≤1000 1≤n,m≤1000 &#xff0c; 序列中的值满足 0≤val≤30000 输入描述&#xff1a; 1.输入包含三行&#xff0c; 2.第一行包含两个正整数n, m&am…

Modbus协议详解4:RTU帧 ASCII帧的差错校验

前面已经分析过RTU帧和ASCII帧的报文区别&#xff0c;细心的朋友应该会发现在两种不同的报文传输模式下都有一个共同的组成部分——差错校验。 这个差错校验在RTU模式和ASCII模式下也不是不相同的。看下面的对比&#xff1a; RTU模式的差错校验&#xff1a; ASCII模式的差错校验…

对GRUB和initramfs的小探究

竞赛时对操作系统启动过程产生了些疑问&#xff0c;于是问题导向地浅浅探究了下GRUB和initramfs相关机制&#xff0c;相关笔记先放在这里了。 内核启动流程 在传统的BIOS系统中&#xff0c;计算机具体的启动流程如下&#xff1a; 电源启动&#xff1a;当计算机的电源打开时&…

CPU眼里的C/C++:1.2 查看变量和函数在内存中的存储位置

写一个很简单的 c 代码&#xff0c;打印一些“地址”&#xff0c; 也就是变量、函数的“存储位置”&#xff1a;当程序被加载到内存后&#xff0c;它们具体是存在哪里&#xff0c;可以用精确的数值来表示&#xff0c;这就是内存地址。 https://godbolt.org/z/Ghh9ThY5Y #inc…

电解电容寿命与哪些因素有关?

电解电容在各类电源及电子产品中是不可替代的元器件&#xff0c;这些电子产品中由于应用环境的原因&#xff0c;使它成为最脆弱的一环&#xff0c;所以&#xff0c;电解电容的寿命也直接影响了电子产品的使用寿命。 一、电解电容失效模式与因素概述 铝电解电容器正极、负极引出…

Java实现ORM第一个api-FindAll

经过几天的业余开发&#xff0c;今天终于到ORM对业务api本身的实现了&#xff0c;首先实现第一个查询的api 老的C#定义如下 因为Java的泛型不纯&#xff0c;所以无法用只带泛型的方式实现api&#xff0c;对查询类的api做了调整&#xff0c;第一个参数要求传入实体对象 首先…

android——自定义控件(编辑框)、悬浮窗

一、自定义编辑框 效果图&#xff1a; 主要的代码为&#xff1a; class EditLayout JvmOverloads constructor(context: Context, attrs: AttributeSet? null, defStyleAttr: Int 0 ) : ConstraintLayout(context, attrs, defStyleAttr) {private var editTitle: Stringpr…

Android12 启动页适配

印象中&#xff0c;在2022年末接到了一个针对Android12启动页适配的需求&#xff0c;当时也使用了一些适配方案&#xff0c;也写了一个Demo&#xff0c;但是最终没有付诸适配行动&#xff1b;当然并不是适配失败&#xff0c;而是根据官方适配方案适配后太丑了… 1024纪念文章&a…

Java中的CAS简述

目录 1、CAS是什么 2、CAS的生活化例子 3、Java中的atomic包 4、unsafe类 5、CAS的缺点及解决方案 小结 1、CAS是什么 CAS&#xff08;Compare and Swap&#xff09;是一种并发编程中的原子操作&#xff0c;用于实现多线程环境下的无锁同步。它是一种乐观锁的实现方式&a…

分布式限流:Redis

目录 1:如何实现分布式限流 2:限流的几种类别 2.1:固定窗口限流 2.2:滑动窗口限流 2.3:漏桶限流 2.4:令牌桶限流 3:实现分布式限流:Redis 3.1:引入Redisson的依赖包 3.2:初始化Redisson 3.3:创建Redisson的限流类 1:如何实现分布式限流 1:把统计用户的使用频率等这些…