数据结构 - 归并排序 | C

news2024/11/18 8:13:11

思路分析

  • 什么是归并?

    • 示例:(归并后的结果copy到原数组)
      在这里插入图片描述
    • 逻辑:
      if (a[begin1] <= a[begin2])
      {tmp[i++] = a[begin1++];}
      else
      {tmp[i++] = a[begin2++];}
      在这里插入图片描述
  • 归并排序
    在这里插入图片描述
    分解到“有序”再归并

递归

  • int middle = (left + right) / 2;
  • [left, middle]→[begin1,end1] ; [middle+1,right]→[begin2,end2]
  • [begin1,end1]→左区间 [begin2,end2]→ 右区间
    (从处理顺序来看,归并排序相当于后序遍历二叉树-左右根,快速排序相当于前序遍历二叉树-根左右)
  • 开辟空间后记得free
// 归并排序递归实现
void _MergeSort(int* a, int left, int right, int* tmp)
{
	assert(a && tmp);

	if (left == right)
		return;

	int middle = (left + right) / 2;
	//[left,  middle] [middle+1,right]
	//[begin1,end1]   [begin2,end2]
	int begin1 = left, end1 = middle, begin2 = middle + 1, end2 = right;

	//递归分解
	_MergeSort(a, begin1, end1, tmp);
	_MergeSort(a, begin2, end2, tmp);

	//merge
	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 + left, tmp + left, sizeof(int) * (right - left + 1));
}
void MergeSort(int* a, int n)
{
	assert(a);
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (!tmp)
	{
		perror("malloc fail");
		exit(-1);
	}

	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
}

迭代

在这里插入图片描述

  • range=1(一个数与一个数归并)可以清楚地看到每组归并间隔两倍 range

  • for (int i = 0; i < n; i += 2 * range)
    在这里插入图片描述

  • range=2(两个数与两个数归并)
    在这里插入图片描述
    通过以上两个示例,不难得出:

  • int begin1 = i, end1 = i + range - 1;

  • int begin2 = i + range, end2 = i + 2 * range - 1;

  • ⭐越界的问题!(修改)

  • 由上可知,begin1<end1<begin2<end2

    • begin1越界 - 正好结束 在这里插入图片描述
    • end1越界:修改end1、begin2、end2的值,并使[begin2,end2]→ 右区间不存在(begin2 > end2)
    • begin2越界:修改begin2、end2的值,并使[begin2,end2]→ 右区间不存在(begin2 > end2)
    • end2越界:修改end2的值
  • 或者也可以选择跳出循环,不处理剩下的数,直接copy

// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
	assert(a);
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (!tmp)
	{
		perror("malloc fail");
		exit(-1);
	}

	int range = 1;
	while (range < n)
	{
		for (int i = 0; i < n; i += 2 * range)
		{
			int begin1 = i, end1 = i + range - 1;
			int begin2 = i + range, end2 = i + 2 * range - 1;
			int j = begin1;

			//越界
			if (end1 >= n)
			{
				end1 = n - 1;
				begin2 = end2 + 1;//begin2 > end2;
			}
			else if (begin2 == n)
			{
				begin2 = end2 + 1;//begin2 > end2;
			}
			else if (end2 >= n)
			{
				end2 = n - 1;
			}
			//merge
			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);

		range *= 2;
	}

	free(tmp);
	tmp = NULL;
}

代码汇总

// 归并排序递归实现
void _MergeSort(int* a, int left, int right, int* tmp)
{
	assert(a && tmp);

	if (left == right)
		return;

	int middle = (left + right) / 2;
	//[left,  middle] [middle+1,right]
	//[begin1,end1]   [begin2,end2]
	int begin1 = left, end1 = middle, begin2 = middle + 1, end2 = right;

	//递归分解
	_MergeSort(a, begin1, end1, tmp);
	_MergeSort(a, begin2, end2, tmp);

	//merge
	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 + left, tmp + left, sizeof(int) * (right - left + 1));
}
void MergeSort(int* a, int n)
{
	assert(a);
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (!tmp)
	{
		perror("malloc fail");
		exit(-1);
	}

	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
}

// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
	assert(a);
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (!tmp)
	{
		perror("malloc fail");
		exit(-1);
	}

	int range = 1;
	while (range < n)
	{
		for (int i = 0; i < n; i += 2 * range)
		{
			int begin1 = i, end1 = i + range - 1;
			int begin2 = i + range, end2 = i + 2 * range - 1;
			int j = begin1;

			//越界
			//end1越界
			if (end1 >= n)
			{
				end1 = n - 1;
				begin2 = end2 + 1;//begin2 > end2;
			}
			else if (begin2 == n)
			{
				begin2 = end2 + 1;//begin2 > end2;
			}
			else if (end2 >= n)
			{
				end2 = n - 1;
			}
			//merge
			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);

		range *= 2;
	}

	free(tmp);
	tmp = NULL;
}

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

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

相关文章

哈希——unordered系列关联式容器

目录 unordered系列关联式容器 概念 unordered_map 无序去重 operator[] unordered_set 无序去重 OJ练习题 重复n次的元素 两个数组的交集 两个数的交集二 底层结构 概念 哈希冲突 闭散列 结点的定义 扩容 字符串取模 插入 查找 删除 闭散列完整代码 开…

安卓远程控制软件哪个好用

如果您曾希望将个人电脑放在口袋里&#xff0c;那么您可能只需要安卓远程访问软件。 没有远程访问应用程序&#xff1a;使用和控制计算机的唯一方法是坐在计算机前并手动输入命令。 使用远程访问应用程序&#xff1a;您可以在世界任何地方通过 Internet 连接从您的安卓平板电…

【30天python从零到一】---第七天:列表和元组

&#x1f34e; 博客主页&#xff1a;&#x1f319;披星戴月的贾维斯 &#x1f34e; 欢迎关注&#xff1a;&#x1f44d;点赞&#x1f343;收藏&#x1f525;留言 &#x1f347;系列专栏&#xff1a;&#x1f319; Python专栏 &#x1f319;请不要相信胜利就像山坡上的蒲公英一样…

计算机组成原理---第五章中央处理器

&#xff08;一&#xff09;CPU 的功能和组成 CPU 的功能 Ⅰ 概述&#xff1a;当程序指令装入内存储器后&#xff0c;CPU 用来自动完成取指令和执行指令的任务。 Ⅱ CPU 的功能&#xff1a;①指令控制 ②操作控制 ③时间控制 ④数据加工 2.CPU 的基本组成 CPU 的基本部分为运…

【论文阅读】[JBHI] VLTENet、[ISBI]

[JBHI] VLTENet 论文连接&#xff1a;VLTENet: A Deep-Learning-Based Vertebra Localization and Tilt Estimation Network for Automatic Cobb Angle Estimation | IEEE Journals & Magazine | IEEE Xplore Published in: IEEE Journal of Biomedical and Health Infor…

9.1 相关分析

学习目标&#xff1a; 如果我要学习相关分析&#xff0c;我可能会按照以下步骤进行&#xff1a; 确定学习相关分析的目的和应用场景&#xff0c;例如研究两个变量之间的相关性、了解变量之间的关系、预测未来趋势等。学习相关分析的基本概念和原理&#xff0c;包括相关系数、…

VS——Visual Studio 2022 社区版——快捷键

VS——Visual Studio 2022 社区版——快捷键官网简介PDF完整PDF编辑编辑&#xff1a;常用快捷方式菜单栏 会显示 快捷键功能搜索大纲 折叠 展开Ctrl M M 切换官网 https://learn.microsoft.com/zh-cn/visualstudio/ide/default-keyboard-shortcuts-in-visual-studio?viewvs-2…

数据结构 — 【排序算法】

目录 1.排序的概念及其运用 1.1排序的概念 1.2排序运用 1.3 常见的排序算法 2.常见排序算法的实现 2.1 插入排序 直接插入排序 希尔排序 2.2 选择排序 直接选择排序 堆排序 2.3 交换排序 冒泡排序 快速排序 2.4 归并排序 2.5 非比较排序 计数排序 基数排序 3.排序算法…

【Unity入门】12.MonoBehaviour事件函数

【Unity入门】MonoBehaviour事件函数 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;常用的事件函数 &#xff08;1&#xff09;start和update方法 之前我们写的脚本&#xff0c;会默认帮助…

4.3 分部积分法

学习目标&#xff1a; 学习分部积分法&#xff0c;我可能会按照以下步骤进行&#xff1a; 理解分部积分法的基本思想。分部积分法是一种通过对积分式中的不同部分进行乘积分解&#xff0c;然后对乘积中的某一项进行积分&#xff0c;对另一项进行微分&#xff0c;从而将原积分式…

NumPy 秘籍中文第二版:五、音频和图像处理

原文&#xff1a;NumPy Cookbook - Second Edition 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 在本章中&#xff0c;我们将介绍 NumPy 和 SciPy 的基本图像和音频&#xff08;WAV 文件&#xff09;处理。 在以下秘籍中&#xff0c;我们将使用 NumPy 对声音和图像进…

叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践

导读&#xff1a; 随着叮咚买菜业务的发展&#xff0c;不同的业务场景对数据分析提出了不同的需求&#xff0c;他们希望引入一款实时 OLAP 数据库&#xff0c;构建一个灵活的多维实时查询和分析的平台&#xff0c;统一数据的接入和查询方案&#xff0c;解决各业务线对数据高效实…

一键构建分布式云原生平台

目录专栏导读一、分布式云原生平台1、应用无所不能2、运行无处不在3、服务千行白业二、分布式云原生平台关键要素1、统一应用管理2、统一流量自治3、统一数据管理4、统一运维三、多云多集群已经广泛应用四、分布式云的优势&#xff1a;1、避免厂商锁定2、满足合规化要求3、增强…

收藏!7个国内「小众」的程序员社区

技术社区是大量开发者的集聚地&#xff0c;在技术社区可以了解到行业的最新进展&#xff0c;学习最前沿的技术&#xff0c;认识有相同爱好的朋友&#xff0c;在一起学习和交流。 国内知名的技术社区有CSDN、博客园、开源中国、51CTO&#xff0c;还有近两年火热的掘金&#xff…

基于决策树及集成算法的回归与分类案例

基于决策树及集成算法的回归与分类案例 描述 本任务基于决策树及集成算法分别实现鲍鱼年龄预测案例和肿瘤分类案例。鲍鱼年龄预测案例是建立一个回归模型&#xff0c;根据鲍鱼的特征数据&#xff08;长度、直径、高度、总重量、剥壳重量、内脏重量、壳重&#xff09;等预测其…

Python:超级大全网上面试题搜集整理(四)

转载参考&#xff1a; python 面试题(高级)_python高级面试题_梦幻python的博客-CSDN博客 cpython pypy_介绍Cython&#xff0c;Pypy Cpython Numba各有什么缺点【面试题详解】_函明的博客-CSDN博客 Cython、PyPy专题开篇 - 知乎 Python抽象类和接口类_python 接口类_代码输…

蓝桥杯客观题知识点

一、异步和同步的在于 有无统一的时钟信号 异步无 同步有 RS485 半双工、异步、串行、差分输入------多级通信&#xff08;USB\键盘等外设&#xff09; RS232 全双工、异步、串行、单端输入------一对一通信 二、组合逻辑电路和时序逻辑电路的区别 组合&#xff1a;任意时…

使用反射重新执行不同的方法

0. 用到的技术 反射获取正在执行的方法名称Class[]数组的获取 1. 为什么要这样做? 情况如下: 当我调用sendCommands方法发送请求时可能会收到errorCode为403也就是代码中的MDS_ERROR,就是当token(mds)失效了这种情况,我们就需要重新刷新token,并且重新执行该方法 假设还有1…

SYN FLOOD攻击和HTTP慢速攻击实验笔记

SYN_FLOOD攻击和HTTP慢速攻击是DDOS攻击的两种方式。 SYN Flood攻击 SYN Flood攻击的原理就是阻断TCP三次握手的第三次ACK包&#xff0c;即不对服务器发送的SYNACK数据包做出应答。由于服务器没有收到客户端发来的确认响应&#xff0c;就会一直保持连接直到超时&#xff0c;当…

产品营销软文怎么写吸引人?

随着互联网的发展&#xff0c;人们获取信息的渠道变得越来越多&#xff0c;其中软文营销成为了众多企业推广自己产品的主要方式之一。那么&#xff0c;软文营销怎么写才能吸引人呢&#xff1f;这里有一些建议&#xff0c;可以帮助你解决这个问题。 要想写出一篇成功的软文&…