【八大排序(七)】归并排序初级篇-递归版

news2024/12/23 11:17:31

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:八大排序专栏⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习排序知识
  🔝🔝


在这里插入图片描述

归并排序

  • 1. 前言
  • 2. 归并排序基本思路
  • 3. 对合并两个有序数组的思考
  • 4. 合并两个有序数组代码实现
  • 5. 归并排序递归版代码实现
  • 6. 总结思考以及拓展

1. 前言

归并排序算法是采用
分治法的一个经典案例
它和数据结构中的二叉树有异曲同工之妙
我们将从如何合并两个有序数组
到如何递归自身达到有序两个方面
给大家介绍归并排序的递归版本

在这里插入图片描述

准备好,大家上车开启归并之旅
(注意:本章排序都按升序讲解)


2. 归并排序基本思路

我们先创建一个无序数组:

int a[]={10,6,7,1,3,9,4,2};

基本思路:

  1. 拆分过程:
  • 要使数组整体有序就要将
  • 左半部分和右半部分变为有序
  • 后进行单次归并排序
  • 将数组拆分为两个部分A和B
  • 要使A数组有序就要将
  • A也拆分为两个部分
  • 使左/右半部分都有序
  • 一直拆分直到数组只有一个元素

画图理解:

在这里插入图片描述

  1. 合并过程:
  • 从左往右将6,10合并为有序
  • 将7,1合并为有序后6,10,7,1再合并
  • 数组的左半部分有序后.走右边
  • 将3,9合并为有序后将4,2合并为有序
  • 再将3.9.4.2合并为有序
  • 至此左右子区间都有序
  • 再将左右子区间归并为有序
  • 使数组整体有序

画图理解:

在这里插入图片描述

这里给大家放出一个动图
帮助大家理解这个过程:

归并排序


3. 对合并两个有序数组的思考

我们由易到难,定义两个有序数组:

int a[]={1,2,3};
int b[]={2,5,6};

方法:

  • 定义两个指针A和B
  • 分别指向两个数组的第一个元素
  • 定义一个数组C接收这两个数组的数据
  • A和B指向的值谁小,谁就放在C中第一个位置
  • 然后对应的指针(A或B)往后走一步
  • 直到走完其中一个数组后停下来

画图理解:

在这里插入图片描述

像这样往后一直走
这里我给出力扣平台的动图视频
帮助大家理解:

合并两个有序数组


4. 合并两个有序数组代码实现

我们刚刚说明了
合并两个有序数组
在原数组中不好操作
所以我们定义一个临时数组tmp
来接收排序好的顺序,最后再拷贝回原数组

while (begin1 < end1 && begin2 < end2)//begin指针指向两个有序数组的第一个元素.end为数组有效范围
	{
		if (a[begin1] < a[begin2])//谁小谁就先进tmp数组
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 < end1)//当其中一个数组走完后.将另外一个数组所有内容直接放进tmp数组
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 < end2)//数组1先走完就将数组2剩下全部内容放进去
	{
		tmp[i++] = a[begin2++];
	}
	//将tmp数组的内容拷贝回a数组
	for (int j = left; j < right; j++)
	{
		a[j] = tmp[j];
	}
}

5. 归并排序递归版代码实现

由于每次都需要二分数组
而且需要为临时数组tmp开辟空间
在原函数上直接递归就不太方便
所以我们设计一个主函数和一个递归函数
方便我们编写代码

主函数:

//归并排序
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);//为临时数组tmp开辟空间
	if (tmp == NULL)
	{
		printf("动态开辟失败");
		exit(-1);
	}
	_MergeSort(a, 0, n - 1, tmp);//_MergeSort为递归函数.传参进行递归过程
	free(tmp);
	tmp = NULL;
}

递归函数:

//归并排序的子程序
void _MergeSort(int* a, int left, int right, int* tmp)
{
	if (left >= right)
	{
		return;
	}
	int mid = (left + right) / 2;
	_MergeSort(a, left, mid, tmp);//进了函数一直递归,直到数组元素为1个后开始归并排序
	_MergeSort(a, mid + 1, right, tmp);//先递归左边再递归右边

	int begin1 = left;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = right;
	int i = left;
	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++];
	}
	//将tmp数组的内容拷贝回a数组
	for (int j = left; j < right; j++)
	{
		a[j] = tmp[j];
	}

}

6. 总结思考以及拓展

算法效率思考:
我们按最坏的情况来计算

  • 归并排序会将数组不断二分
    一共分为 log2n 这么多层

  • 而第一次二分的数组要走n/2个元素
    二分完有两个数组也就是走n个元素

  • 以此类推,第二次二分完的数组
    有四个,每个数组需要走n/4个元素
    第二层也就要走n个元素

  • 可以推算出每层要走n个元素

一共log~2~n层,每层遍历n个元素
时间复杂度为: O(N*log2N)


拓展:

归并排序最坏情况下
时间复杂度为: N * (log2N)+1-N ∈ O(Nlog2N)
归并排序最好情况下
时间复杂度为: (N * log2N)/2 ∈ O(N
log2N)

详细推导过程可以参考:归并算法分析

既然归并有递归版本
那么肯定就有非递归版本
还是那句话:
正在与别人拉开差距的地方
往往就是研究得更加深入的地方


🔎 下期预告:归并排序非递归版 🔍

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

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

相关文章

在数组中各位置上计算该位置以前所有元素的累加结果(Nan值视为0)numpy.nancumsum()

【小白从小学Python、C、Java】 【等级考试500强双证书考研】 【Python-数据分析】 在数组中各位置上计算该位置以前 所有元素的累加结果&#xff08;Nan值视为0&#xff09; numpy.nancumsum() [太阳]选择题 以下说法错误的是&#xff1a; import numpy as np a np.array([[n…

使用兮克 2.5G 交换机将北京联通 EPON 改为 ODI 猫棒接入

使用兮克 2.5G 交换机将北京联通 EPON 改为 ODI 猫棒接入 最近入手了兮克2.5G交换机&#xff08;兮克SKS1200-8GPY1XF&#xff09;&#xff0c;有 8 个 2.5G 电口和 1 个 10G SFP 光口&#xff1b;支持多种组网模式&#xff0c;其中一种是支持使用猫棒接入&#xff0c;由路由器…

聊聊微服务到底该如何划分

背景 现在动不动就是微服务架构&#xff0c;但是微服务划分的合理与否会极大的影响开发过程中的复杂度&#xff0c;划分的重要性不言而喻&#xff0c;但是在微服务划分这条路上并没有银弹&#xff0c;有的说DDD可以解决微服务的划分问题&#xff0c;吕哥想说的是那只是理论上的…

Linux常用命令——gcc命令

在线Linux命令查询工具 gcc 基于C/C的编译器 补充说明 gcc命令使用GNU推出的基于C/C的编译器&#xff0c;是开放源代码领域应用最广泛的编译器&#xff0c;具有功能强大&#xff0c;编译代码支持性能优化等特点。现在很多程序员都应用GCC&#xff0c;怎样才能更好的应用GCC…

Linux---上传和下载、压缩和解压

1. 上传下载 可以通过FinalShell工具&#xff0c;方便的和虚拟机进行数据交换。 在FinalShell软件的下方窗体中&#xff0c;提供了Linux的文件系统视图&#xff0c;可以方便的&#xff1a; 浏览文件系统&#xff0c;找到合适的文件&#xff0c;右键点击下载&#xff0c;即可…

STL中set与map介绍

目录 一. 键值对1. 关联式容器2. pair3. 应用场景 二. set1. set的介绍2. set的使用3. multiset的介绍 三. map1. map的介绍2. map的使用3. multimap的介绍 一. 键值对 ​ 用来表示具有一一对应关系的一种结构&#xff0c;该结构中一般只包含两个成员变量key和value。key代表键…

Draw.io 高阶用法

drawio是一款非常不错画流程图的软件&#xff0c;而且是免费的&#xff0c;但大部分图形以2D为主&#xff0c;有时候 却需要一些3D效果来增强方案 举个例子&#xff1a; 需要变成这样&#xff0c;看起来更3D 方法&#xff1a; 先拖入一个圆形&#xff0c;把限制比例去掉&a…

【C数据结构】队列_Queue

目录 队列_Queue 【1】队列的概念及结构 【2】节点队列的实现 【2.1】队列的各个接口 【2.2】队列的初始化 【2.3】队列栈的释放 【2.4】队尾入队列 【2.5】队头出队列 【2.6】获取队列头部元素 【2.7】获取队列尾部元素 【2.8】获取队列中有效元素个数 【2.9】检测…

图像 检测 - CenterNet: Objects as Points (arXiv 2019)

CenterNet: Objects as Points - 目标作为点&#xff08;arXiv 2019&#xff09; 摘要1. 引言2. 相关工作3. 准备工作4. 目标作为点4.1 3D 检测4.2 人体姿态估计 5. 实施细节6. 实验6.1 目标检测6.1.1 附加实验 6.2 3D 检测6.3 姿态估计 7. 结论References附录A&#xff1a;模型…

Nginx安装Windows、Linux | 正向代理、反向代理、负载均衡

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Nginx Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;也可用作电子邮件代理服务器和通用TCP/UDP代理服务器。它是一个轻量级的Web服务器&#xff0c;可以作为静…

[进阶]Java:线程概述、线程创建方式

什么是线程&#xff1f; 线程(thread)是一个程序内部的一条执行路径。我们之前启动程序执行后&#xff0c;main方法的执行其实就是一条单独的执行路径。程序中如果只有一条执行路径&#xff0c;那么这个程序就是单线程的程序。 多线程是什么&#xff1f; 多线程是指从软硬件上…

【现代数据架构】面向初创公司的现代数据堆栈

“为工作使用正确的工具&#xff01;” 这句话一开始听起来很简单&#xff0c;但在实际方面实施起来却非常复杂。早期的初创公司发现很难选择生态系统中可用的各种工具&#xff0c;因为它们的数据将如何演变是非常不可预测的。 需要现代数据堆栈 在过去 10 年中&#xff0c;软件…

c++11 标准模板(STL)(std::basic_ios)(四)

定义于头文件 <ios> template< class CharT, class Traits std::char_traits<CharT> > class basic_ios : public std::ios_base 类 std::basic_ios 提供设施&#xff0c;以对拥有 std::basic_streambuf 接口的对象赋予接口。数个 std::basic_ios…

VMware Integrated OpenStack 7.3 - 支持 vSphere 8.0U1 和 NSX 4.1 并向下兼容

VMware Integrated OpenStack 7.3 - 支持 vSphere 8.0U1 和 NSX 4.1 并向下兼容 VMware 支持的 OpenStack 发行版&#xff1a;在 VMware 虚拟化技术之上运行企业级 OpenStack 云 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-vio-7/&#xff0c;查看最新版。原创…

极易搭建的代码托管平台Gitea

这礼拜有点霉啊&#xff0c;先是日常自用的机器上&#xff0c;SSD 挂了&#xff0c;彻底识别不了的那种 隔了两天&#xff0c;用来写文章用的小机器上&#xff0c; 500G 的机械硬盘也挂了&#xff0c;重新格了一下&#xff0c;挂在玩客云上当个下载盘用吧 好在都有备份&#xf…

[进阶]Java:文件字节输出流、文件拷贝、资源释放

文件字节输出流&#xff08;FileOutputStream&#xff09;写数据出去的API 流的关闭和刷新 代码演示如下&#xff1a; ​​​​​​​ public class OutputStreamDemo04 {public static void main(String[] args) throws Exception {//1.创建一个文件字节输出流管道与目标文件…

WPF开发txt阅读器14:通过C#代码设计UI布局

文章目录 需求分析C#代码UI设计 txt阅读器系列&#xff1a; 需求分析和文件读写目录提取类&#x1f48e;列表控件与目录字体控件绑定&#x1f48e;前景/背景颜色书籍管理系统&#x1f48e;用树形图管理书籍语音播放&#x1f48e;播放进度显示&#x1f48e;快进快退&#x1f48…

ad18学习笔记六:ad18官方在线文档

这个挺有用&#xff0c;反正我是没找到离线的、完整的、详细的软件说明文档&#xff0c;只有去官网看在线的&#xff0c;有点卡&#xff0c;还是全英文的。 具体的位置直接进官网&#xff0c;比如这个&#xff1a; Board Region | Altium Designer 18.0 User Manual | Docume…

BOSHIDA AC DC电源模块在光纤通信设备的应用

BOSHIDA AC DC电源模块在光纤通信设备的应用 随着科技的不断发展&#xff0c;光纤通信技术逐渐成为人们日常生活和工作中广泛采用的一项技术。在光纤通信设/备中&#xff0c;稳定的电源模块是其正常运转的关键。AC DC电源模块在光纤通信设/备的应用也越来越广泛。 AC DC电源模…

清华青年AI自强作业hw3_1:用线性回归模型拟合MNIST手写数字分类

清华青年AI自强作业hw3_1&#xff1a;用线性回归模型拟合MNIST手写数字分类 实现过程思路分析逻辑回归二分类模型训练结果分析 相关链接 一起学AI系列博客&#xff1a;目录索引 hw3_1&#xff1a;用线性回归模型拟合MNIST手写数字分类 初步体验Tensorflow编程环境体会用回归模…