[ 数据结构 -- 手撕排序算法第七篇 ] 归并排序

news2025/2/4 20:50:34

文章目录

  • 前言
  • 一、常见的排序算法
  • 二、归并排序的基本思想
  • 三、归并排序
    • 3.1 归并排序的递归版本
    • 3.2 归并排序的非递归版本
  • 四、归并排序的特性总结


前言

手撕排序算法第七篇:归并排序!
从本篇文章开始,我会介绍并分析常见的几种排序,例如像插入排序,冒泡排序,希尔排序,选择排序,快速排序,堆排序,归并排序等等!
这篇文章我先来给大家手撕一下归并排序

大家可以点下面的链接去阅读其他的排序算法:
C语言手撕排序算法


正文开始!

一、常见的排序算法

在这里插入图片描述

二、归并排序的基本思想

归并排序(MERGE-SORT)是建立在归并操作上的一种有序的排序算法,该算法是采用分治法(Divide and Conquer)是一个非常典型的应用。将已经有序的子序列合并,得到有序的序列;即先使每个子序列有序,再使子序列有序。若将两个有序表合并成一个有序表,称为二路归并。

核心步骤根据图来理解:
在这里插入图片描述
在这里插入图片描述

三、归并排序

3.1 归并排序的递归版本

void _MergeSort(int* a,int begin,int end,int* tmp)
{
	if (begin >= end)
		return;
	int mid = (begin + end) >> 1;
	//[begin,mid][mid+1,end]
	_MergeSort(a,begin,mid,tmp);
	_MergeSort(a,mid+1,end,tmp);

	//归并[begin,mid][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,(end-begin+1)*sizeof(int));
	for (int i = begin; i <= end; i++)
	{
		a[i] = tmp[i];
	}
}
void MergeSort(int* a,int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	assert(tmp);
	_MergeSort(a,0,n-1,tmp);

	free(tmp);
}
void TestMergeSort()
{
	int a[] = { 10,6,7,3,9,1,4,2 };
	printf("排序前:");
	PrintArray(a, sizeof(a) / sizeof(a[0]));
	MergeSort(a,sizeof(a) / sizeof(a[0]));
	printf("排序后:");
	PrintArray(a, sizeof(a) / sizeof(a[0]));
}
int main()
{
	TestMergeSort();
	return 0;
}

在这里插入图片描述

3.2 归并排序的非递归版本

画图分析如下:
在这里插入图片描述
在这里插入图片描述
我们可以发现利用上述的思想就可以实现非递归排序。

但是在这里随意加一个数字,程序就崩溃了,这是为什么呢?

先来实验结果:

在这里插入图片描述
我先利用6个数给大家讲讲,数太多了,分析起来不容易理解!

在这里插入图片描述

在这里只有可能end1,begin2,end2可能会越界,所以在归并之前控制约束条件即可!

完整代码如下

//归并排序的非递归版本
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	assert(tmp);
	int gap = 1;
	while (gap<n)
	{
		//间距为gap的是一组,两两归并
		for (int i = 0; i < n; i += 2*gap)
		{
			int begin1 = i, end1 = i+gap-1;
			int begin2 = i+gap, end2 = i+2*gap-1;
			int index = i;
			//end1越界,修正即可
			if (end1 >= n)
			{
				end1 = n - 1;
			}
			//begin2越界,证明后半区间不存在
			if (begin2 >= n)
			{
				begin2 = n;
				end2 = n-1;
			}
			//begin2存在,end2越界,修正end2即可
			if (begin2 < n && end2 >= n)
			{
				end2 = n - 1;
			}

			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 , tmp , n * sizeof(int));
		gap *= 2;
	}
	free(tmp);
}
void TestMergeSort()
{
	int a[] = { 10,6,7,3,9,1};
	printf("排序前:");
	PrintArray(a, sizeof(a) / sizeof(a[0]));
	MergeSortNonR(a, sizeof(a) / sizeof(a[0]));
	printf("排序后:");
	PrintArray(a, sizeof(a) / sizeof(a[0]));
}
int main()
{
	TestMergeSort();
	return 0;
}

在这里插入图片描述
此时归并排序的非递归版本就实现啦!

四、归并排序的特性总结

  1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多实在解决在磁盘中的外排序问题。
  2. 时间复杂度:O(N*logN).
  3. 空间复杂度:O(N).
  4. 稳定性:稳定.

(本章完!)

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

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

相关文章

深度学习秘籍

显式构造 隐式构造 loss通常是一个标量 batchsize越小其实越好 回归 预测的是一个连续 softmax回归是一个多分类问题 分类 预测是一个离散值 Huber RoBust Loss, 也就是通常所说SmoothL1损失 常用命令 import torch import torchvision from torchvision import transformsso…

ContentProvider的介绍和使用

文章目录ContentProviderContentProvider简介运行时权限Android权限机制详解在程序运行时申请权限访问其他程序当中数据ContentResolver的基本用法读取系统联系人信息创建自己的ContentProvider创建ContentProvider的步骤实现跨程序数据共享ContentProvider 如果我们想要实现跨…

浅拷贝深拷贝递归

常见的基本数据类型&#xff1a;Number、String 、Boolean、Null和Undefined 引用数据类型&#xff1a;Object、Array、Function 1&#xff09;基本数据类型&#xff1a;存储在栈内存中,可以直接访问到该变量的值。 2&#xff09;引用数据类型&#xff1a;存储在堆内存中,每…

有哪些数据统计软件适合初学者使用?

前段时间写过一篇“数据分析工具”的内容&#xff0c;周末有伙伴私信问我有没有什么适合初学者、业务人员的&#xff0c;更简单一点的数据可视化软件。 所以今天来分享下我在做数据分析时用过的几个简单易上手的数据可视化软件。 先放上目录&#xff1a; 数据统计收集类——简…

谷粒学院——Day12【整合阿里云短信服务、首页登录和注册】

用户登录业务介绍 一、单一服务器模式 早期单一服务器&#xff0c;用户认证。 缺点&#xff1a;单点性能压力&#xff0c;无法扩展。 二、SSO(single sign on)模式 分布式&#xff0c;SSO(single sign on)模式 优点&#xff1a; 用户身份信息独立管理&#xff0c;更好的…

关于安科瑞电气安全产品在医药工业洁净厂房的电气工程设计与应用

摘要&#xff1a; 近年来&#xff0c;医药工业洁净厂房的电气工程设计得到了快速发展和广泛关注&#xff0c;研究其相关课题有着重要意义。首先介绍了供电系统与配电设备的设置&#xff0c;分析了洁净厂房的电气照明设计&#xff0c;并结合相关实践经验&#xff0c;从探测器选…

智能无障碍轮椅——ESP8266总体介绍及ESP-01S入门调试

文章目录ESP8266 介绍ESP8266的多种型号1. DT-062. ESP-01和ESP-01S【左边ESP-01S&#xff0c;右边ESP-01】3. ESP-12F两种开发方式1. AT指令开发方式2. SDK开发方式固件烧录方法1. 硬件烧录工具2. 软件烧录工具WiFi模块工作模式&#xff1a;1. AP模式2. STA模式3. STAAP共存ES…

宏、条件编译(#ifdef)、#include(头文件包含)、#error和 #pragma的区别、#和##的含义和应用

1、在C语言预处理阶段&#xff0c;编译器首先对代码的处理时&#xff1a;先去注释&#xff0c;再宏替换。 2、在源文件的任何地方&#xff0c;宏都是可以定义的&#xff0c;与是否在函数内外无关。 3、宏的作用范围是&#xff1a;从定义处开始&#xff0c;往后的直到程序结束…

C++(老百科)

学了这么久的c,你们有没有想过一个问题:什么是c?(这还用问么,不大街上随便抓一个陌生人都知道)(那你现在给我抓个看看) C简介 C是一种计算机高级程序设计语言&#xff0c;由C语言扩展升级而产生 &#xff0c;最早于1979年由本贾尼斯特劳斯特卢普在AT&T贝尔工作室研发。––…

easyexcel读取excel将数据存到mysql【一个简单的例子】

读取excel 1 xml里面增加maven <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version> </depen…

项目管理软件适用于初创公司吗

我注意到关于小型团队的一件事是&#xff0c;在这种热情的背后隐藏着一家需要帮助的公司。他们通常缺乏职责结构&#xff0c;但这可能不是他们的主要需求。太多的结构会扼杀那些在较小的初创型公司中经营节目的企业家精神的努力&#xff0c;但他们几乎总是需要更有效的流程和一…

分布式理论之CAP定理

CAP定理介绍 CAP定理&#xff08;CAP theorem&#xff09;&#xff0c;又被称作布鲁尔定理&#xff08;Brewers theorem&#xff09;&#xff0c;它指出对于一个分布式计算系统来说&#xff0c;不可能同时满足以下三点 选项具体意义一致性&#xff08;Consistency&#xff09…

linux TxBytes RxBytes 探究

测试平台 &#xff1a;NXP LS1043A ARM64 内核版本&#xff1a; 两台设备通过网口eth2 对接。设备1发包&#xff0c;设备2收包&#xff0c;观察两设备 TX RX 包数、字节数。 1、准备数据包 流量仪设置包长1024, 抓取从流量仪发包&#xff0c;wireshark显示length 1020字…

即时通讯音视频开发之音频编解码技术的学习

总是有人问我研究音频编解码要看什么书&#xff0c;其实这是一个很难回答的问题&#xff0c;原因有很多&#xff1a; 做工程首先一个问题就是和课本学习不同&#xff0c;不是看书能解决的。 音频编解码技术在国内研究的人很少&#xff0c;包括总体的音频技术国外也研究不多…

攻防世界ics-06

攻防世界ics-06 题目描述&#xff1a;云平台报表中心收集了设备管理基础服务的数据&#xff0c;但是数据被删除了&#xff0c;只有一处留下了入侵者的痕迹。 打开场景&#xff0c;查看页面。 但凡有超链接的都点一遍&#xff0c;发现只有“报表中心可以打开”。 选择日期范围&a…

go 库 viper 配置解析神器

文章目录1. 简介2. 安装3. 建立默认值4. 读取配置文件5. 获取 key/value 方法5.1 Get() 方法5.2 IsSet()、GetStringMap()、GetStringMap() 方法6. 命令行选项7. 访问嵌套的键8. 写入配置文件9. 监控并重新读取配置文件10. 从io.Reader中读取11. Unmarshal12. 环境变量13. 远程…

【Three.js入门】图形用户界面GUI、BufferGeometry创建矩形、随机生成多个随机颜色的三角形

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

第四章操作系统测试

一. 单选题&#xff08;共24 题&#xff0c;72.0分&#xff09; (单选题,3.0分)用户编写的程序中所使用的地址是&#xff08; C &#xff09;。 A. 内存地址 B. 物理地址 C. 逻辑地址 D. 绝对地址 解释&#xff1a;逻辑地址&#xff1a;用户空间中使用的一种地址又称相对地址 …

一行 Python 代码能实现什么丧心病狂的功能?

手头有 109 张头部 CT 的断层扫描图片&#xff0c;我打算用这些图片尝试头部的三维重建。基础工作之一&#xff0c;就是要把这些图片数据读出来&#xff0c;组织成一个三维的数据结构&#xff08;实际上是四维的&#xff0c;因为每个像素有 RGBA 四个通道&#xff09;。这个数据…

gitLab

GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的web服务。下面是使用步骤 1. 注册 进入注册页面&#xff08;需要公司的人提供地址&#xff09;例如&#xff1a; http://xx.xxx.xx.xx:18000/users/sign_in …