数据结构——归并排序

news2024/11/23 15:44:18

坚持看完,结尾有思维导图总结

这里写目录标题

  • 归并排序的思路
    • 归并算法的图解
      • 具体程序
    • 对性质的分析
    • 归并排序的非递归版本
    • 总结

归并排序的思路

首先第一个问题是,什么是归并排序?
官方的说法: 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法
即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

按照我的理解
就是首先,先把数组按照一半一半的方式切分(我把这个一半的数组叫做半数组),先把半数组有序排列,然后再利用两个有序数组的合并合并出原来的有序数组

归并排序的思路是什么?
按照定义中我的理解
这个问题可以进一步划分为

1.大数组如何拆成两个数组?
2.如何得到有序数组?
3.两个有序数组是如何合并的?

通过分析可以知道
一个大数组,假设数组元素是这样
在这里插入图片描述
通过分解,能够回答第 1 ,2 个问题
如果每次都取到数组中间位置,就能够将数组进行切分,所以我们要得到中间位置

当将数组切分到最小数组,每个数组中只有一个元素的时候,这个数组天然就是有序的

第三个问题,当得到最小的区间的时候,就能够进行单趟的排序
单趟的排序就是要进行两个有序数组的合并

有序数组的合并的思路是:
1.两个有序数组的元素依次比较,将小的元素先放进临时数组中
2.任意一个数组走完的时候,剩下的其余元素全部放进临时数组内
3.将临时数组拷贝回原数组

在这里插入图片描述

归并算法的图解

在这里插入图片描述
需要注意的是:
原数组a 下标和tmp 的下标是一致的

具体程序


void _mergesort(int*a ,int begin,int end,int* tmp)
{
	int mid = begin + (end-begin)/2;
	//切分终止
	if(begin >= end)
	{
		return ;
	}
	//切分数组
	_mergesort(a,begin,mid,tmp);
	_mergesort(a,mid+1,end,tmp);

	//单趟有序数组合并

	int begin1 = begin,end1 = mid;
	int begin2 = mid+1,end2 = end;
	int j = begin;
	while(begin1<=end1 && begin2<=end2)
	{
		if(a[begin1] <= a[begin2])
		{
			//小的放在tmp 上,并且保持稳定
			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+begin,tmp+begin,sizeof(int)*(end-begin+1));
}

void MergeSort(int*a,int len)
{
	int* tmp = (int*)malloc(len*sizeof(int));
	if(tmp == NULL)
	{
		exit(-1);
	}
	_mergesort(a,0,len-1,tmp);
	free(tmp);
	tmp = NULL;
}

对性质的分析

这里主要解决几个问题
1.归并算法的时间复杂度,空间复杂度
2.归并算法的稳定性

由于归并排序是二叉树结构,递归深度为 logn
每次排序为 n 次
所以时间复杂度为 n*logn

空间复杂度 为 n
额外开辟的空间为 n
递归深度使用空间为 logn

稳定性,稳定
因为每次单趟排序,当数字相等时,默认使用第一个数组(即前数组)的数据
所以相同数据的顺序没有被打乱,因此是稳定的

归并排序的非递归版本

第一个问题,非递归的版本如何实现?

上面我们使用递归,把数组拆分
从大数组变成了元素个数为1的有序数组
然后再利用有序数组合并完成单趟排序

如果我们能过手动控制数组元素的个数
从一个,到两个,到四个的有序数组合并,就能实现归并排序的非递归方式

对应的图解就是
在这里插入图片描述

这里需要提出一个问题
在这里设定的 grip 可以看成每个子数组的元素个数
begin1 ,end1 是 第一个子数组的开始和结束
begin2,end2是 第二个自数字的开始和结束
除了 begin1 是第一个元素,其余的 end1,begin2,end2都是由 begin 和 grip 计算出来的
end1 ,begin2,end2 就会有越界的可能
就需要进行讨论

end1 越界和 begin2 都是说明数组2不存在,可以跳过本次排序,直接进行下一次排序
end 2越界则说明数组2的结束需要调整,调整为原数组的结束

对应的程序为

void MergeSortNonR(int* a, int len)
{
	int* tmp = (int*)malloc(sizeof(int) * len);
	if (tmp==NULL)
	{
		exit(-1);
	}
	int begin, end, begin1, end1, begin2, end2, grip;
	grip = 1;
	//当 grip 超过 len 的时候结束
	while (grip < len)
	{
		//单趟
		for (int i = 0; i < len; i += grip)
		{
			//begin end 是归并后的数组的头尾,
			//begin1 ,end1 是 第一个子数组的开始和结束,
			//begin2,end2是 第二个自数字的开始和结束

			begin = begin1 = i;
			end1 = begin1 + grip - 1;
			begin2 = end1 + 1;
			end = end2 = begin2 + grip - 1;
			//前两种数组2不存在的情况直接进行下一次排序
			if (end1 > len-1 || begin2 > len-1)
			{
				break;
			}
			if (end2 > len-1)
			{
				end2 = end = len-1;
			}

			//单趟归并
			int j = begin;
			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 + begin, tmp + begin, (end - begin + 1) * sizeof(int));
		}
		grip *= 2;
	}
	free(tmp);
	tmp = NULL;
}

总结

在这里插入图片描述

希望大家看完,能够有所收获
如果有错误,请指出我一定虚心改正
动动小手点赞
鼓励我输出更加优质的内容

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

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

相关文章

pikachu靶场-7 不安全的文件下载和上传

不安全的文件下载和上传 不安全的文件下载 文件下载&#xff08;unsafedownload&#xff09;漏洞概述 很多网站都会提供文件下载功能&#xff0c;即用户可以通过点击下载链接&#xff0c;下载到链接所对应的文件。 但是&#xff0c;如果文件下载功能设计不当&#xff0c;则…

基于51单片机的数字频率计设计

仿真原理图&#xff1a; 程序运行图&#xff1a; 部分程序&#xff1a; #define LED_GLOBAL 1 #include "led.h" /******************************************************************************************* *函数名称&#xff1a;delay_us(uint us) *函数…

15.JavaScript 02

文章目录一、DOM简单学习&#xff1a;为了满足案例要求1、DOM知识点简单学习2、事件简单学习3、案例1&#xff1a;电灯开关二、BOM1、概念2、组成3、Window&#xff1a;窗口对象1. Window窗口对象知识点2. 案例2&#xff1a;轮播图4、Location&#xff1a;地址栏对象1. Locatio…

手写Spring5(资源加载Spring.xml解析和注册Bean对象)

文章目录目标设计思路项目结构一、实现1、资源加载接口定义和实现获取ClassPath下的文件信息获取指定文件路径的方式读取文件信息获取HTTP的方式读取云服务的文件2、包装资源加载器定义和实现-策略模式的体现包装资源加载器实现3、Bean定义读取接口4、Bean定义抽象类实现5、解析…

[激光原理与应用-53]:《激光焊接质量实时监测系统研究》-4-激光焊接系统软件设计

目录 前言&#xff1a; 4.1 操作系统和开发平台 4.1.1 Windows2000 操作系统概述 4.1.2 虚拟仪器开发平台软件 LabWindows/CVI 4.2 总体软件设计 4.2.1 数据采集程序 4.2.2 软件实现的功能 4.2.2.1 主机软件的数据采集 4.2.2.2 主机软件的数据分析&#xff08;核心&am…

暗棕红色粉末ICG-COOH, ICG Carboxlaic acid,181934-09-8,ICG和PEG链接可在体内长循环

英文名&#xff1a;ICG-COOH ICG Carboxlaic acid CAS No:181934-09-8 外观&#xff1a;暗棕红色粉末 溶解度&#xff1a;在水或甲醇中溶解 纯度&#xff1a;90% 结构式&#xff1a; 西安凯新近红外荧光染料Near IRDyes激发和发射波长和颜色图 ICG NHS ester的NHS可以和蛋白…

八、闭包高级、对象、构造函数、实例化

闭包高级、对象、构造函数、实例化 闭包高级 函数被定义时生成[[scope]]->生成scope chain -> scope chain中存着上级的环境。 函数被执行的前一刻&#xff08;预编译过程&#xff09;&#xff0c;生成自己的AO&#xff0c;排到scope chain的最顶端。 函数执行完毕的…

基于天鹰算法优化的lssvm回归预测-附代码

基于天鹰算法优化的lssvm回归预测 - 附代码 文章目录基于天鹰算法优化的lssvm回归预测 - 附代码1.数据集2.lssvm模型3.基于天鹰算法优化的LSSVM4.测试结果5.Matlab代码摘要&#xff1a;为了提高最小二乘支持向量机&#xff08;lssvm&#xff09;的回归预测准确率&#xff0c;对…

DFA的最小化

一、实验目的 1&#xff0e;熟练掌握DFA与NFA的定义与有关概念。 2&#xff0e;理解并掌握确定的有穷自动机的最小化等算法。 二、实验要求 输入&#xff1a;DFA 输出&#xff1a;最小化的DFA 三、实验过程 1&#xff0e;化简DFA关键在于把它的状态集分成一些两两互不相交…

一、ArrayList源码解读

ArrayList源码 一、前言 ArrayList在日常的开发中使用频率非常高&#xff0c;但是JDK是如何去设计ArrayList的&#xff0c;这就需要我们好好去了解底层实现原理&#xff0c;这样使用起来才能做到心中有数&#xff1b;当然&#xff0c;还能应付面试。本篇文章会围绕ArrayList的…

王道操作系统网课笔记合集

介绍 操作系统是什么&#xff1f; 计算机结构大概分为四层&#xff1a; 用户应用程序操作系统硬件 操作系统是一类系统软件&#xff0c;调度硬件资源&#xff0c;合理分配管理软件&#xff08;因此操作系统又被称作资源管理器&#xff08;resource manager&#xff09;&…

简洁而优美的结构 - 并查集 | 一文吃透 “带权并查集” 不同应用场景 | “手撕” 蓝桥杯A组J题 - 推导部分和

&#x1f49b;前情提要&#x1f49b; 本章节是每日一算法的并查集&带权并查集的相关知识~ 接下来我们即将进入一个全新的空间&#xff0c;对代码有一个全新的视角~ 以下的内容一定会让你对数据结构与算法有一个颠覆性的认识哦&#xff01;&#xff01;&#xff01; ❗以…

【Unity 3D 从入门到实践】Unity 3D 预制体

目录 一&#xff0c;预制体介绍 二&#xff0c;创建预制体 三&#xff0c;实例化预制体 一&#xff0c;预制体介绍 预制体是 Unity 3D 提供的保存游戏对象组件和属性的方法&#xff0c;通过预制体可以快速的实例化挂载不同组件的游戏对象&#xff0c;从而减少开发难度&…

使用光隔离的调制器在电机控制中进行安全、准确的隔离电流传感

介绍 在工业电机或伺服控制应用中&#xff0c;准确的电流测量是控制回路的一部分。目前的测量不仅需要尽可能准确&#xff0c;还需要安全可靠。 工业电机或伺服控制系统通常包含高压&#xff0c;在过流或短路等故障事件中&#xff0c;这些情况需要快速检测和整流&#xff0c…

Android开发基础

文章目录前言工程项目结构hello world界面布局代码操作新页面页面间跳转简单计算器的实现思路前端控件传递数据后端实现逻辑两个Activity之间传值发送数据返回数据SQLite简单使用利用语句写在后面写在后面前言 安卓(Android)是一种基于Linux内核的开源操作系统 使用java、kot…

不就是性能测试吗?竟让我一个月拿了8个offer,其中两家都是一线大厂

随着互联网的发展&#xff0c;单机软件的逐渐减少&#xff0c;系统从单机步入“云”时代&#xff0c;软件系统功能和规模也越来越庞大&#xff0c;盗版也越来越难&#xff0c;用户规模也越来越大&#xff0c;企业盈利随之爆发式地增长。 随着用户数量的增多&#xff0c;系统稳…

Chrome浏览器修改用户资料(User Data)的存放位置

2022.12.13一、 原先采用的在快捷方式中修改目标的方法&#xff0c;没有效果。二、创建链接1. 复制2. 删除3. 创建链接mklink参考用于缓解C盘压力&#xff0c;将浏览器用户数据存放于其他的指定位置。简单记录一下操作步骤。 其中用户数据可以如此查找&#xff0c;在浏览器地址…

数字虚拟人发展简史

虚拟人的发展史就是技术的发展史 作为元宇宙时代的基石&#xff0c;虚拟人的发展历史与制作技术的进步高度相关。在元宇宙概念中&#xff0c;未来每个用户都将依托虚拟人作为自己的化身进入虚拟世界中探索&#xff0c;要达成这个目的&#xff0c;就要求数字虚拟人不仅拥有人的…

java计算机毕业设计ssm智慧消防维保系统后端设计与实现3cmg0(附源码、数据库)

java计算机毕业设计ssm智慧消防维保系统后端设计与实现3cmg0&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都…

【毕业设计】微信小程序校园跑腿系统 校园跑腿小程序 校园跑腿微信小程序

一、前言 大学是一个小社会&#xff0c;我们在学校学习到专业知识的时候&#xff0c;有会遇到很多形形色色的任务&#xff0c;但最重要的依旧是社会经历。很多大学生都会想着在大学闯出一片新天地&#xff0c;所以他们往往会选择自己或者带上志同道合的朋友来一起创业。一次好…