归并排序 (递归+非递归)

news2024/9/21 1:22:59

文章目录

  • 1. 归并排序 递归
    • 1.基本思想
    • 2. 使用两个函数完成归并
    • 3. 递归结束条件
    • 4.时间复杂度与空间复杂度计算
      • 1. 时间复杂度
      • 2. 空间复杂度
    • 5. 代码
  • 2. 归并排序 非递归
    • 1. 思想
    • 2. 越界问题
      • 1. .end1 beign2 end2 越界
        • 方式 1
        • 方式 2
      • 整体拷贝与拷贝一部分,归并一部分的区别
      • 2. begin2 end2 越界
        • 方式 1
        • 方式 2
      • 3. end2 越界
    • 3. 代码

1. 归并排序 递归

1.基本思想

主要使用了 分治思想 即 大事化小 ,先使每个子序列有序,子使序列段有序,将两个有序表合并成一个有序表

在这里插入图片描述

2. 使用两个函数完成归并

在这里插入图片描述

因为想要malloc只开辟一块空间,而不是设置在mergesort1函数中每递归一次开辟一块空间,极大节省开辟空间开销

3. 递归结束条件

在这里插入图片描述

当下标 left 与right 相等时,正好为一个数,即 return 返回

在这里插入图片描述

当数组为0,就会发生 left>right,区间不存在

4.时间复杂度与空间复杂度计算

1. 时间复杂度

在这里插入图片描述

归并整个过程,类似一颗满二叉树,
调用次数:2^h-1=N h=logN
每一层遍历次数 :N
整体时间复杂度为 O(N*logN)

2. 空间复杂度

在这里插入图片描述

刚开始 开辟了 一个大小为n的 临时数组 tmp
空间复杂度为 O(N)

在这里插入图片描述

正常来说,我们递归也会产生函数栈帧,调用次数 —— 空间复杂度即O(logN)

整体空间复杂度为 O(N+logN)
但是由于大o的渐进表示法 即 O(N)

5. 代码

void mergesort1(int* a, int left, int right,int* tmp)
{
if (left >= right)//递归 结束条件
{
return;
}
int mid = (left + right) / 2;
// [left ,mid] [mid+1 ,right] 
mergesort1(a, left, mid,tmp);
mergesort1(a, mid + 1, right,tmp);
// 合并两个有序数组,并将其赋给临时数组tmp,最后拷贝原数组中(合并一部分,拷贝一部分)
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int i = left;//由于部分合并,所以i从left开始
while (begin1<=end1&&begin2<=end2)
{
if (a[begin1] < a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
 //若出了循环后,也有可能在两个数组有剩余的情况
while (begin1 <= end1)//若 [begin1,end1]数组有剩余,直接赋值到tmp数组
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)//若 [begin2,end2]数组有剩余,直接赋值到tmp数组
{
tmp[i++] = a[begin2++];
}
 //第一种拷贝方式
memcpy(a+left, tmp+left, sizeof(int) * (right - left + 1));
 //第二种拷贝方式
/*for (i = 0; i <= right; i++)
{
a[i] = tmp[i];
}*/
}
void mergesort(int* a, int n)// 归并排序 递归
{
int* tmp = (int*)malloc(sizeof(int) * n);
mergesort1(a, 0, n - 1,tmp);
free(tmp);
tmp = NULL;
}

2. 归并排序 非递归

1. 思想

在这里插入图片描述

将一个数组 ,通过gap分为几组进行合并,gap每次扩大2倍,gap<n
合并方式与递归相同
第一个数组的 begin1 改为 i
第一个数组的 end1 改为 i+gap-1
第二个数组 的 begin2改为 i+gap
第二个数组的 end2 改为 i+2*gap-1

2. 越界问题

在这里插入图片描述

int a[] = { 6,1,2,7,9,3,4,5,6,8 };
共有10个数,下标到9
1.end1 beign2 end2 越界
2.begin2 end2 越界
3.end2 越界

1. .end1 beign2 end2 越界

在这里插入图片描述

方式 1

直接break
因为右边没有数据存在,所以就算是进入循环中剩余区间中的数也不会发生改变

在这里插入图片描述

方式 2

修正区间
因为begin2 与end2区间不存在,
end1=n-1 end1设置成边界
设置一个不存在的区间
begin2 =n
end2= n-1
begin2>end2 不进入循环 合并,直接拷贝回剩余的区间

在这里插入图片描述

整体拷贝与拷贝一部分,归并一部分的区别

以上一个的end1 begin2 end2 越界为例
同样使用break
拷贝一部分,归并一部分就能存在剩余的区间

在这里插入图片描述

整体拷贝就会丢掉剩余的区间

在这里插入图片描述
在这里插入图片描述

2. begin2 end2 越界

在这里插入图片描述

方式 1

直接break
因为右边没有数据存在,所以就算是进入循环中剩余区间中的数也不会发生改变

在这里插入图片描述

方式 2

修正区间
设置一个不存在的区间
begin2 =n
end2= n-1
begin2>end2 不进入循环 合并,直接拷贝回剩余的区间

在这里插入图片描述

3. end2 越界

修正end2区间
end2=n-1 ,而n-1正好为边界

在这里插入图片描述
在这里插入图片描述

3. 代码

void mergesortNonR(int* a, int n)//归并排序 非递归
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	int gap = 1;
	int i = 0;
	int j = 0;
	while (gap < n)
	{
		for (i = 0; i < n; i += 2*gap)
		{
			//[ i , i+gap-1][i+gap,i+2*gap-1]
			int begin1 = i;
			int end1 = i + gap - 1;
			int begin2 = i + gap;
			int end2 = i + 2*gap-1 ;
			j = i;

			//1. end1 begin2 end2 越界
			if (end1 >= n)//end2是下标的存在 ,最多取到 n-1
			{
				break;
			}
			//if (end1 >= n)//修正区间
			//{
			//	end1 = n - 1;
			//	begin2 = n;
			//	end2 = n - 1;
			//}
			//2.  begin2 end2 越界
			else if (begin2 >= n)
			{
				break;
			}
			/*else if (begin2 >= n)
			{
				begin2 = n;
				end2 = n - 1;
			}*/
			//3. end2 越界
			else if (end2 >= n)
			{
				end2 = n - 1;
			}
			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) * (end2-i+1));
		}
		gap *= 2;
	}
	free(tmp);
	tmp = NULL;
}

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

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

相关文章

数据库与身份认证:数据库的基本概念

什么是数据库 数据库&#xff08;database&#xff09;是用来组织、存储和管理数据的仓库。 当今世界是一个充满着数据的互联网世界&#xff0c;充斥着大量的数据。数据的来源有很多&#xff0c;比如出行记录、消费记录、浏览的网页、发送的消息等等。除了文本类型的数据&…

【知识图谱】(task1)知识图谱概论

note 知识图谱技术要素 文章目录note一、语言与知识二、知识图谱的起源三、知识图谱的价值四、知识图谱的技术内涵4.1 知识图谱是交叉领域4.2 技术内涵&#xff08;1&#xff09;基于图的表示学习&#xff08;2&#xff09;图数据存储和查询&#xff08;3&#xff09;知识图谱…

企业庆典年会活动如何邀约媒体记者到现场报道

媒体邀约是指企业或者是公司根据其发生的公关事件&#xff0c;比如展览展会、新品上市以及合作签约等事宜&#xff0c;向特定的媒体发出邀请&#xff0c;如果邀请得到媒体的通过之后&#xff0c;那么相应的媒体就会到公司的现场进行实时采访和报道&#xff0c;之后还会在国内的…

node.js的四种内置模块

目录 1、node.js内置模块的概念 2、fs内置模块 3、path内置模块 4、url内置模块 5、http内置模块 1、node.js内置模块的概念 node.js的内置模块也叫作node.js的核心模块&#xff0c;它是node.js自带的模块&#xff0c;在下载了node.js后就会有的&#xff0c;并不需要从外…

猿如意中的【Code:: Blocks】工具详情介绍

文章目录一、工具名称二、下载安装渠道2.1 什么是猿如意&#xff1f;2.2 如何下载猿如意&#xff1f;2.3 如何在猿如意中下载开发工具Code:: Blocks&#xff1f;三、工具介绍四、Code::Blocks 功能介绍4.1、VC 6.04.2、Code::Blocks4.3、Dev-C4.4 Visual Studio4.5、C-Free五、…

BF706和BF609的Flash Program新技巧,可以使用第三方插件

作者的话 CCES来做Flash Program&#xff0c;需要CMD&#xff0c;然后敲一大堆的命令&#xff0c;刚开始搞的时候&#xff0c;会觉得很麻烦&#xff0c;那么是否有更简单的办法呢&#xff1f;在Blackfin处理器里&#xff0c;我找到了一个第三方插件&#xff0c;用这个插件就可…

Uniapp 如何用离线打包工程制作自定义调试基座

如何用离线打包工程制作自定义调试基座 Tips⚠️&#xff1a; 确保版本一致,请确保从HBuilderX导出的打包资源的HBuilderX的版本号和App离线SDK发布的版本号是一致的&#xff0c;如下2张图里的版本号&#xff1a; 打开原生iOS工程 1、在打包原生工程里找到 control.xml文件&a…

单向链表理解——java

概述 单线链表&#xff1a;单向链表又叫单链表&#xff0c;是链表的一种。由节点构成&#xff0c;head指针指向第一个称为表头节点,而终止指向最后一个null指针 特点 链表连接的方向都是单向的链表的访问要通过顺序从头部开始链表是使用指针进行构造的列表是由一个一个节点组…

Python读取Excel文件

最近需要用到Python来操作excel表&#xff0c;读取表格内容到数据库。所以就搜索了相关资料。 查找了一下&#xff0c;可以操作excel表的几个库有以下几个&#xff1a; openpyxl 这个是推荐使用的库&#xff0c;可以读写Excel 2010以上格式&#xff0c;以.xlsx结尾的文件。 x…

SpringBoot+Vue项目校园二手交易平台

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

HCI opcode

HCI控制命令由两个字节的OpCode定义&#xff0c;每个OpCode由一个字节的OGF&#xff08;OpCode Group Field&#xff09;和一个字节的OCF&#xff08;OpCode Command Field&#xff09;组成。参考&#xff1a; HCI Command Packet Command的数据包格式如下图&#xff1a; 其中…

海量数据下查询慢、数据不一致难题如何解?看某游戏公司的技术实践

导语&#xff1a; 复杂架构的危害是隐性且持续增长的&#xff0c;尤其在海量数据处理的业务场景下&#xff0c;导致系统吞吐量增长、各功能模块相互影响&#xff0c;且数据重复、维护困难。某游戏公司就面临这样的困境&#xff0c;在寻求解决方案的过程中&#xff0c;携手Ocean…

通用的异常处理程序机制与处理返回值方案

通用的异常处理程序机制与返回值方案文章目录通用的异常处理程序机制与返回值方案现状示例方案原理步骤总结附完整代码现状相信很多人都为处理错误返回值代码都烦恼过。例如&#xff1a;一个程序嵌套了10个方法&#xff0c;嵌套最深的方法一旦有个业务错误代码&#xff0c;那么…

如何通过文档改善用户体验和客户关系

文档对你的员工和客户来说都是一个宝贵的信息来源。你策划和分享的每一个教程、"如何做 "的文章和指南都可以改善用户体验和客户关系。 在这个数字时代&#xff0c;每个人都希望立即得到答案&#xff0c;很少或没有人际互动&#xff0c;一个坚实的知识库软件使你领先…

TIOBE12月编程语言榜发布:C++首超Java!

本月TIOBE更新了榜单&#xff0c;其中变化最大的莫过于C以0.12%微弱优势&#xff0c;总市场份额首次超过了Java。 在今年6月份的时候&#xff0c;TIOBE的CEOPaul Jansen曾做出过预测&#xff0c;C将会是下一个超越Java的语言。果然在最新版本的C 20的推动下&#xff0c;超越了…

模板方法模式(python)

一、模式定义 1.模板方法模式(Template Method Pattern)&#xff1a;定义一个操作中算法的框架&#xff0c;而将一些步骤延迟到子类中&#xff0c;模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 2.模板方法是一种类行为型模式。 二、模式结构 …

斩获三奖 | 国产BI行业唯一获奖,Smartbi荣获36氪、数据猿等多项荣誉

入选36氪新经济之王年度企业近日&#xff0c;36氪WISE2022 新经济之王盛会隆重举行&#xff0c;会上正式发布了“WISE2022 新经济之王年度企业”名册&#xff0c;思迈特软件成功斩获“WISE2022 新经济之王年度企业”荣誉&#xff0c;成为国产BI行业唯一获奖品牌。据了解&#x…

scrapy爬虫框架

scrapy爬虫框架一 scrapy架构介绍二 安装指南三 创建项目3.1 创建爬虫项目3.2 创建爬虫3.3 启动爬虫3.4 pycharm中运行四 scrapy解析数据五 settings相关配置六 持久化方案七 全站爬取cnblogs文章八 中间件一 scrapy架构介绍 Scrapy一个开源和协作的框架&#xff0c;其最初是为…

在线购物电商网站毕业设计,网上购物商城系统设计与实现,毕业设计怎么写论文毕设源码开题报告需求分析怎么做

项目背景和意义 目的&#xff1a;伴随着互联网技术的不断发展和完善&#xff0c;在人们的生活和工作的各个方面&#xff0c;互联网都有着非常重大的影响。伴随着国内电子商务行业的迅猛发展&#xff0c;消费者现在能够轻松的实现足不出户的&#xff0c;仅仅通过网络购物平台就可…

【工作经历分享】软件测试求职真的难,但是我还是从7K涨到了14K

上个礼拜刚好转正了&#xff0c;三个月试用期&#xff0c;五月份换的工作。 现在这份工作&#xff0c;相比上一份确实好很多&#xff0c;比如工资直接涨了一倍&#xff0c;7到14&#xff0c;13薪&#xff0c;朝九晚六&#xff0c;从不加班&#xff0c;项目也简单&#xff0c;包…