【排序】归并排序(递归和非递归)

news2024/10/6 14:25:44

归并排序

    • 前言
    • 图解
    • 大致思路
    • 代码实现
      • 递归
      • 非递归
    • 时间复杂度和空间复杂度

在这里插入图片描述

前言

这是我讲的最后一个排序了,归并排序难度不大,也是分治的思想。

归并排序时间复杂度是在N*logN里面还是比较优的,毕竟实现起来的是完全二分的,但是差就差在了空间复杂度。

还是老样子,先给图解:

图解

在这里插入图片描述

大致思路

根据图也就看到了,是一个后序的处理,先分组再排序,跟快排不一样,快排是先排序再分组。

每一趟都是:先找最中间位置的下标mid,然后直接分成[left, mid] 和 [mid + 1, right],然后等这两个有序了之后,再按顺序合并到一块。

但是排序前要开一个大小和原数据相同的数组。每一趟排完后,合并的时候得再这个新开的数组中合并,不然直接原数组合并的话是无法实现的。

代码实现

递归

这里写了一个子函数,因为不能每次都创建一个数组,要提前就开好。

//归并排序子函数
void _MergeSort(int* a, int left, int right, int* tmp)
{
	if (left >= right)
		return;

	int mid = (left + right) / 2;

	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);

	//左区间
	int begin1 = left, end1 = mid;
	//右区间
	int begin2 = mid + 1, end2 = right;
	
	int i = begin1;

	//归并两个区间
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] > a[begin2])
			tmp[i++] = a[begin2++];
		else
			tmp[i++] = a[begin1++];
	}

	//右区间归并完了,左区间没归并完
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}

	//左区间归并完了,右区间没归并完
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

	//每次递归排序的位置是从left开始的,所以拷贝的时候要从这个位置拷贝
	memcpy(a + left, tmp + left, (right - left + 1) * sizeof(int));
}
 
 //归并排序
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(n * sizeof(int));
	if (tmp == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

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

非递归

归并排序递归改非递归与斐波那契数列改为非递归的类似,要用到循环。

定义几个变量,当前趟的i,每次归并的时候两区间间隔位置gap
begin1 = i, end1 = i + gap - 1;
begin2 = i + gap, end2 = i + 2 * gap - 1;

每次归并的就是[begin1, end1] 和 [begin2, end2]两组的数。

大概图解:
在这里插入图片描述

代码实现

每次拷贝一大段:(推荐)

//归并非递归
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(n * sizeof(int));
	if (tmp == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	//初始gap为1
	int gap = 1;

	while (gap < n)
	{
		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;

			//调整越界区间
			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[begin2++];
				else
					tmp[j++] = a[begin1++];
			}

			//右区间归并完了,左区间没归并完
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}

			//左区间归并完了,右区间没归并完
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}

		}
		memcpy(a, tmp, n * sizeof(int));
		gap *= 2;
	}
}

第二种:每次拷贝一小段

//归并非递归
void MergeSortNonR2(int* a, int n)
{
	int* tmp = (int*)malloc(n * sizeof(int));
	if (tmp == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	//初始gap为1
	int gap = 1;

	while (gap < n)
	{
		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;

			//调整越界区间
			if (end1 >= n || begin2 >= n)
			{
				break;
			}
			else if (end2 >= n)
			{
				end2 = n - 1;
			}

			int sn = end2 - begin1 + 1;
			int begin = begin1;
			int j = begin1;

			//归并两个区间
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] > a[begin2])
					tmp[j++] = a[begin2++];
				else
					tmp[j++] = a[begin1++];
			}

			//右区间归并完了,左区间没归并完
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}

			//左区间归并完了,右区间没归并完
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			memcpy(a + begin, tmp + begin, sn * sizeof(int));
		}
		gap *= 2;
	}
}

时间复杂度和空间复杂度

时间O(N * logN)
空间O(N),每次排序前都要开辟相同大小的数组。

到此结束。

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

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

相关文章

2023第十届大唐杯省赛心得体会总结

第十届“大唐杯”全国大学生新一代信息通信技术大赛结束&#xff0c;分享一下2023第十届大唐杯省赛的相关经验。 年初研究生组就开始报名了&#xff0c;所以这回也是摩拳擦掌&#xff0c;加上大唐杯的认可度很高&#xff0c;今年的情况只会更卷&#xff0c;需要掌握一定的通信…

java数据结构学习第三期

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…

4.17-4.18学习总结

MD5 MD5: 1、压缩性 2、容易计算 3、抗修改性 4、弱抗碰撞 5、强抗碰撞 为什么需要MD5&#xff1f; 存储一些敏感信息的时候&#xff0c;如果不进行加密会出现安全问题。 例如&#xff1a;系统登录的密码&#xff0c;如果数据库中的密码采用明文&#xff0c;一旦数据库泄…

扬帆优配|多路资金扎堆博弈,顶级游资章盟主3天爆买21个亿

4月20日&#xff0c;中科曙光&#xff08;603019.SH&#xff09;盘中稳步拉升&#xff0c;最终收涨9.99%&#xff0c;股价一举刷出了历史新高&#xff0c;达到了54.71元/股&#xff0c;全天的成交额也高达97.43亿元。 盘后发表的龙虎榜数据显现&#xff0c;知名游资章盟主的常用…

Qt Quick - PageIndicator

Q 理论使用总结 一、概述二、简单使用例子1. SwipeView 和 PageIndicator2. StackLayout 和 PageIndicator 三、常用属性四、定制化 一、概述 PageIndicator用于指示含有多个页面的容器中&#xff0c;当前处理活动的页。记住&#xff0c;这个只是指示当前的活动页&#xff0c;…

java IO流进阶 对象处理流, 转换流, 打印流

目录 一、对象处理流 1.作用 : 2.序列化和反序列化 : 3.ObjectOutputStream : 1 概述 2 演示 4.ObjectInputStream : 1 概述 2 演示 5.关于序列化的细节 : 6.标准输入输出流&#xff1a; 二、转换流 1.概述 : 2.InputStreamReader : 3.OutputStreamWriter : 三、打印…

GB/T28181国标视频监控平台TINYGBS实现监控视频直播的详细搭建流程

TinyGBS是基于GB/T28181-2016(公共安全视频监控联网系统信息传输、交换、控制技术要求)开发的成熟的、敏捷的、产品化的视频汇聚平台&#xff0c;支持标准的监控设备的接入和管理&#xff0c;在多个应用场景中成功落地。实现实时视频调阅、设备控制(云台控制、聚焦控制、拉框放…

GeoDataFrame 应用:公园分布映射至subzone

0 问题描述 我们知道新加坡的monument分布&#xff1a;Monuments-Data.gov.sg 我们又知道新加坡的subzone信息&#xff1a; Master Plan 2019 Subzone Boundary (No Sea) - Datasets - Dataportal.asia 我们希望生成一个 dataframe&#xff0c;表示每一个subzone有几个monumen…

Django REST Framework(DRF)框架之认证Authentication与权限Permission

DRF框架之认证与权限 认证与权限认证(Authentication)权限(Permission) 认证和权限的使用创建用户用于验证配置认证与权限&#xff08;全局&#xff09;视图指定认证与权限&#xff08;局部&#xff09; 自定义权限概述创建自定义权限类使用自定义权限类 使用TokenAuthenticati…

LeetCode二叉树的相关题目

110. 平衡二叉树 方法&#xff1a;递归 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullpt…

漫谈大数据 - HiveSQL总结(一)库表操作

导语&#xff1a;针对hive各种数据库操作&#xff0c;内部表、外部表、分区表、分桶表的表属性查看修改操作以及hive数据的导入与导出详解。 hive简介&#xff1a; hive是基于Hadoop的一个数据仓库工具&#xff0c;用来进行数据提取、转化、加载&#xff0c;这是一种可以存储、…

双系统安装Windowslinux

文章目录 1.1 联想小新windows10重装1.2 宏基暗影骑士windows10重装2.1 ubuntu18.04重装1&#xff09;清理空间并制作U盘启动2&#xff09;ubuntu分区 3.1 ros安装4.1 deb包安装5.1 网络设置6.1 VSCode环境配置 1.1 联想小新windows10重装 bioss设置 ①微软官网制作u盘启动 ②…

微信小程序PHP+python+nodejs+springboot+vue 电影院订票选座系统

管理员的主要功能有&#xff1a; 1.管理员输入账户登陆后台 2.个人中心&#xff1a;管理员修改密码和账户信息 3.会员管理&#xff1a;对注册的会员信息进行删除&#xff0c;查询&#xff0c;添加&#xff0c;修改 4.电影分类管理&#xff1a;对电影的分类信息进行添加&#xf…

python+nodejs+springboot+vue 教学师生互动答疑系统

然后遵循软件常规开发流程&#xff0c;首先针对系统选取适用的语言和开发平台&#xff0c;根据需求分析制定模块并设计数据库结构&#xff0c;再根据系统总体功能模块的设计绘制系统的功能模块图&#xff0c;流程图以及E-R图。然后&#xff0c;设计框架并根据设计的框架编写代码…

浅学WebFlux--构建一个响应式的SpringBoot服务

前言 看惯了SpringMVC&#xff0c;最近在闲来之余抽空了解了一下Spring早已发布并支持的一种新web框架-WebFlux。由于这玩意的使用需要具备的基础是Reactive programming 的理解、Reactor 的基础以及熟练的java8 lambda使用。但是并不影响笔者摸着石头过河……在此做个浅学笔记…

【三十天精通Vue 3】第十二天 Vue 3 过滤器详解(已废弃)

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 引言一、Vue 3 过滤器概述1.1 过滤器的简介1.2 过滤器的作用1.3 过…

创建Vue3.0工程

1.使用 vue-cli 创建 官方文档&#xff1a;创建一个项目 | Vue CLI (vuejs.org) ## 查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上 vue --version ## 安装或者升级你的vue/cli npm install -g vue/cli ## 创建 vue create vue_test ## 启动 cd vue_test npm run se…

7年时间,从功能测试到测试开发月薪30K,有志者事竟成

突破自己的技术瓶颈并不是一蹴而就&#xff0c;还是需要看清楚一些东西&#xff0c;这里也有一些经验和见解跟大家分享一下。同样是职场人士&#xff0c;我也有我的经历和故事。在工作期间&#xff0c;我有过2年加薪5次的小小“战绩”&#xff08;同期进入公司的员工&#xff0…

番外12:ADS导出到AD变为PCB文件

番外12&#xff1a;ADS导出到AD变为PCB文件并嘉立创制板 番外12&#xff1a;ADS导出到AD变为PCB文件&#xff0c;此处的示例为功率放大器&#xff01; STEP 1: 从ADS导出dxf文件 打开制作好的版图文件&#xff0c;在原有基础上打好散热孔和固定孔&#xff0c;散热孔半径0.63…

PCB阻焊桥存在的DFM(可制造性)问题,华秋一文告诉你

PCB表面的一层漆&#xff0c;称为阻焊油墨&#xff0c;也就是PCB线路板阻焊油墨。阻焊油墨是PCB线路板中非常常见、也是主要使用的油墨&#xff0c;一般90%都是绿色&#xff0c;但也有杂色油墨&#xff1a;红色、蓝色、黑色、白色、黄色等。 阻焊油墨的作用就是绝缘&#xff0…