归并排序—C语言实现

news2024/11/26 19:29:40

前言

        🥰在学数据结构的第一节课就知道了数据结构课程是要管理并且学会操作数据,当然操作数据首先想到的就是数据的排序,排过顺序的数据的使用价值才够大。前面我们学习了顺序表也学习了链表等等,这些就是储存数据的方法,下面我们来看一看传说中的归并排序的特点与效率怎么样。😍

归并排序

归并排序基本属性
中文名归并排序
外文名Merge Sort
发明者约翰·冯·诺伊曼
稳定性稳定
时间复杂度O(n log n)
空间复杂度T(n)


 

        归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

算法思路

        归并排序算法有两个基本的操作,一个是分,也就是把原数组划分成两个子数组的过程。另一个是治,它将两个有序数组合并成一个更大的有序数组。

        将待排序的线性表不断地切分成若干个子表,直到每个子表只包含一个元素,这时,可以认为只包含一个元素的子表是有序表。
        将子表两两合并,每合并一次,就会产生一个新的且更长的有序表,重复这一步骤,直到最后只剩下一个子表,这个子表就是排好序的线性表。

归并操作的工作原理如下(非递归形式):

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针超出序列尾将另一序列剩下的所有元素直接复制到合并序列尾

如下图所示 初始的数组是{ 16, 17, 13, 10, 9, 15, 3, 2, 5, 8, 12, 1, 11, 4, 6 }排序过程如下:

归并排序算法实现思想个人理解_CurryCoder的博客-CSDN博客_归并排序思想

        下面还有动图的演示初始数据为{ 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 }排序的详细过程。

 递归代码

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
		return;

	int mid = (begin + end) / 2;

	// [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 i = begin1;
	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));
}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	_MergeSort(a, 0, n - 1, tmp);

	free(tmp);
}

非递归代码

类型一(修正边界法) 

void MergeSortNonR1(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			// [i,i+gap-1][i+gap, i+2*gap-1]
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			if (end1 >= n)
			{
				end1 = n - 1;
				begin2 = n;
				end2 = n - 1;
			}
			else if(begin2 >= n)
			{
				begin2 = n;
				end2 = n - 1;
			}
			else if(end2 >= n)
			{
				end2 = n - 1;
			}
			int j = begin1;
			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, tmp, sizeof(int) * n);
		gap *= 2;
	}
	free(tmp);
}

类型二(越界跳出归并法)

void MergeSortNonR2(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	int gap = 1;
	while (gap < n)
	{
		//printf("gap=%d->", gap);
		for (int i = 0; i < n; i += 2 * gap)
		{
			// [i,i+gap-1][i+gap, i+2*gap-1]
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			// end1越界或者begin2越界,则可以不归并了
			if (end1 >= n || begin2 >= n)
			{
				break;
			}
			else if (end2 >= n)
			{
				end2 = n - 1;
			}
			int m = end2 - begin1 + 1;
			int j = begin1;
			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) * m);
		}

		gap *= 2;
	}

	free(tmp);
}

 总结

        归并排序和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。

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

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

相关文章

2021机器学习阶段性复盘

文章目录 特征选择一、GBDT和Xgboost简介二、 GBDTLR协同过滤&#xff0c;SVD的劣势&#xff1a;极大化似然估计Wide&DeepxDeepFM朴素贝叶斯SVM转为拉格朗日函数转为对偶问题 决策树分类交叉熵损失函数数据预处理连续型特征为什么取对数 深度学习激活函数的作用Softmax与Si…

剑指offer64.求1+2+...+n

看到题脑子里就有了想法&#xff0c;这还不简单&#xff0c;直接用递归啊&#xff0c;return一个nsumNums(n-1)写完之后发现到了0你得终止但是不能用if等语句你没办法终止&#xff0c;想了大概十分钟放弃了&#xff0c;这没办法终止啊&#xff0c;然后看了题解。 class Soluti…

QCFS-related work

一、代码 def replace_maxpool2d_by_avgpool2d(model): # 将模型中的所有MaxPool2d层替换为AvgPool2d层。for name, module in model._modules.items(): # 函数使用递归方式遍历模型的所有模块&#xff0c;通过model._modules.items()获取模型的子模块以及它们对应的名称。if …

Java电子招投标采购系统源码-适合于招标代理、政府采购、企业采购

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…

【Elasticsearch】文档操作

目录 3.文档操作 3.1.新增文档 3.2.查询文档 3.3.删除文档 3.4.修改文档 3.4.1.全量修改 3.4.2.增量修改 3.5.总结 3.文档操作 3.1.新增文档 语法&#xff1a; POST /索引库名/_doc/文档id {"字段1": "值1","字段2": "值2"…

软件测试当中的测试用例模板,仅供参考

测试用例这块知识、经验&#xff0c;小酋在前面陆续都讲完了。这章提供几种用例模板&#xff0c;作为这块知识的收尾。 - 1 - 测试用例&#xff08;主指功能测试用例模板&#xff09;的内容通常包括测试目标&#xff08;目的&#xff09;&#xff0c;需求标示&#xff08;一般…

Background-2 盲注关卡 sqli-Labs Less5-Less-6

文章目录 一、Less-5-less-6一、利用left(database(),1)进行尝试1.查看版本号2.查看数据库的长度3.猜测数据库的第一位 二、利用substr()&#xff0c;ascii()函数进行尝试三、利用regexp()获取&#xff08;2&#xff09;中users表中的列四、利用ord()&#xff0c;mid函数获取us…

elasticsearch插件ik分词器,无法启动解决方案

首先7以后的版本一定要与es的版本保持一致下载包只能下载这个路径的文件&#xff0c;版本号与自己的es版本保持一致 https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.6.0/elasticsearch-analysis-ik-8.6.0.zip这里可以直接替换 docker容器无法启动&…

SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“

一、现象说明 最近在调试 RabbitMQ 程序的时候&#xff0c;日志里如下错误&#xff1a; SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/cod…

排序算法笔记-快速排序

文章目录 笔记简介时间复杂度空间复杂度解题模版练习题 笔记 简介 快速排序&#xff1a;确定分界数&#xff0c;左边小于分界&#xff0c;右边大于分界数&#xff0c;通过递归来不断重置分界数划分区域&#xff0c;直至完成排序 时间复杂度 最优 n*logn 最差 n^2 空间复杂…

找工作不用愁!送你一份Salesforce顾问面试秘籍(下)(含答案)

作为SaaS行业的先驱&#xff0c;Salesforce的发展一路高歌猛进。在Salesforce生态系统中不仅能学习到最新的技术&#xff0c;而且比其他行业的同岗位享有更高的薪水&#xff0c;这也驱使了越来越多人加入Salesforce大军。 在之前的文章中&#xff0c;自由侠部落为学习者梳理了…

Qt6之QSetting读取为空或失败

一、目的 QSetting终极目的是&#xff0c;模糊平台&#xff0c;一套方法可以同时写入或者读取配置文件及注册表。 二、问题 QSetting确实兼顾了平台&#xff0c;linux、mac、windows三大平台均能使用&#xff0c;但就像所有事物一样&#xff0c;大一统的背后必定要做出一些让步…

STM32 Proteus仿真水箱水塔水位温度控制系统DS18B20 -0065

STM32 Proteus仿真水箱水塔水位温度控制系统DS18B20 -0065 Proteus仿真小实验&#xff1a; STM32 Proteus仿真水箱水塔水位温度控制系统DS18B20 -0065 功能&#xff1a; 硬件组成&#xff1a;STM32F103C8单片机 LCD1602显示器ADC220V转3.3V电路DS18B20温度多个按键&#xf…

刚刚出炉,速看7月编程语言排行榜

2023年已经过半&#xff0c;最新一期的编程语言排行榜你看了吗&#xff1f;刚刚&#xff0c;全球知名编程语言社区TIOBE公布了7月榜单&#xff0c; TIOBE 7 月 TOP 15 编程语言&#xff1a; 详细榜单可参考官网&#xff1a; https://www.tiobe.com/tiobe-index/ 在众多编程语…

openpnp - 伺服JAWD7502的参数读取

文章目录 openpnp - 伺服JAWD7502的参数读取概述笔记备注END openpnp - 伺服JAWD7502的参数读取 概述 设备用的双Y轴用到了伺服JAWD7502, 准备将参数读出来, 以备不时之需. 笔记 JAWD7502直接提供了USB接口, 连到电脑就行. 不用准备特别的通讯线. USB接口类型是MicroUSB U…

智能优化算法——哈里鹰算法(Matlab实现)

目录 1 算法简介 2 算法数学模型 2.1.全局探索阶段 2.2 过渡阶段 2.3.局部开采阶段 3 求解步骤与程序框图 3.1 步骤 3.2 程序框图 4 matlab代码及结果 4.1 代码 4.2 结果 1 算法简介 哈里斯鹰算法(Harris Hawks Optimization&#xff0c;HHO)&#xff0c;是由Ali Asghar Heid…

IME SoftInputWindow窗口添加

IME SoftInputWindow窗口添加 1、时序图2、InputMethodService#onCreate()3、Dialog添加到WMS android12-release1 1、时序图 输入法应用继承InputMethodServiceframeworks/base/core/java/android/view/inputmethod/InputMethodManager.java frameworks/base/core/java/andro…

【JAVA】数据类型,类型转换与提升,运算符,标识符命名规则

&#x1f349;内容专栏&#xff1a;【JAVA】 &#x1f349;本文脉络&#xff1a;数据类型&#xff0c;类型转换与提升&#xff0c;运算符&#xff0c;标识符命名规则 &#x1f349;本文作者&#xff1a;Melon_西西 &#x1f349;发布时间 &#xff1a;2023.7.12 目录 1. 字面常…

【数据结构】数据结构的基本概念

文章目录 思维导图数据结构的基本概念和术语数据结构三要素逻辑结构存储结构数据的运算 重要知识总结 思维导图 数据结构的基本概念和术语 数据&#xff1a;数据是信息的载体。是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。数据…

【计算机视觉 | 目标检测 | 图像分割】arxiv 计算机视觉关于目标检测和图像分割的学术速递(7 月 12 日论文合集)

文章目录 一、检测相关(7篇)1.1 3D detection of roof sections from a single satellite image and application to LOD2-building reconstruction1.2 Towards exploring adversarial learning for anomaly detection in complex driving scenes1.3 Unveiling the invisible: …