数据结构——排序算法——归并排序

news2024/12/22 20:13:17

将两个有序数组合并为一个有序数组

在第二个列表向第一个列表逐个插入的过程中,由于第二个列表已经有序,所以后续插入的元素一定不会在前面插入的元素之前。在逐个插入的过程中,每次插入时,只需要从上次插入的位置开始,继续向后寻找插入位置即可。这样一来,我们最多只需要将两个有序数组遍历一次就可以完成合并。

vector<int> merge(vector<int> arr1, vector<int> arr2)
{
	vector<int> result;
	int index1 = 0, index2 = 0;
	while (index1 < arr1.size() && index2 < arr2.size()) {
		if (arr1[index1] <= arr2[index2]) {
			result[index1 + index2] = arr1[index1];
			index1++;
		}
		else {
			result[index1 + index2] = arr2[index2];
			index2++;
		}
	}
	// 将剩余数字补到结果数组之后
	while (index1 < arr1.size()) {
		result[index1 + index2] = arr1[index1];
		index1++;
	}
	while (index2 < arr2.size()) {
		result[index1 + index2] = arr2[index2];
		index2++;
	}
	return result;
}

将两个无序数组合并为一个有序数组

我们可以把数组不断地拆成两份,直到只剩下一个数字时,这一个数字组成的数组我们就可以认为它是有序的。然后通过上述合并有序列表的思路,将 1 个数字组成的有序数组合并成一个包含 2 个数字的有序数组,再将 2 个数字组成的有序数组合并成包含 4 个数字的有序数组…直到整个数组排序完成。

 void mergeSort(vector<int> arr) {
	if (arr.size() == 0) return;
	vector<int> result = mergeSort(arr, 0, arr.size() - 1);
	// 将结果拷贝到 arr 数组中
	for (int i = 0; i < result.size(); i++) {
		arr[i] = result[i];
	}
}

// 对 arr 的 [start, end] 区间归并排序
 vector<int> mergeSort(vector<int> arr, int start, int end) {
	// 只剩下一个数字,停止拆分,返回单个数字组成的数组
	if (start == end) return vector<int>{arr[start]};

	int middle = (start + end) / 2;
	// 拆分左边区域
	vector<int> left = mergeSort(arr, start, middle);
	// 拆分右边区域
	vector<int> right = mergeSort(arr, middle + 1, end);
	// 合并左右区域
	return merge(left, right);
}

归并排序的优化:减少临时空间的开辟

为了减少在递归过程中不断开辟空间的问题,我们可以在归并排序之前,先开辟出一个临时空间,在递归过程中统一使用此空间进行归并即可。


// 将 result 的 [start, middle] 和 [middle + 1, end] 区间合并
void merge(vector<int> arr, int start, int end, vector<int> result) 
{
	int end1 = (start + end) / 2;
	int start2 = end1 + 1;
	// 用来遍历数组的指针
	int index1 = start;
	int index2 = start2;
	while (index1 <= end1 && index2 <= end) {
		if (arr[index1] <= arr[index2]) {
			result[index1 + index2 - start2] = arr[index1++];
		}
		else {
			result[index1 + index2 - start2] = arr[index2++];
		}
	}
	// 将剩余数字补到结果数组之后
	while (index1 <= end1) {
		result[index1 + index2 - start2] = arr[index1++];
	}
	while (index2 <= end) {
		result[index1 + index2 - start2] = arr[index2++];
	}
	// 将 result 操作区间的数字拷贝到 arr 数组中,以便下次比较
	while (start <= end) {
		arr[start] = result[start++];
	}
}


void mergeSort(vector<int> arr) 
{
	if (arr.size() == 0) return;
	vector<int> result;
	mergeSort(arr, 0, arr.size() - 1, result);
}

// 对 arr 的 [start, end] 区间归并排序
void mergeSort(vector<int> arr, int start, int end, vector<int> result)
{
	// 只剩下一个数字,停止拆分
	if (start == end) return;
	int middle = (start + end) / 2;
	// 拆分左边区域,并将归并排序的结果保存到 result 的 [start, middle] 区间
	mergeSort(arr, start, middle, result);
	// 拆分右边区域,并将归并排序的结果保存到 result 的 [middle + 1, end] 区间
	mergeSort(arr, middle + 1, end, result);
	// 合并左右区域到 result 的 [start, end] 区间
	merge(arr, start, end, result);
}

请添加图片描述

原地归并排序

实现一

// 将 arr 的 [start, middle] 和 [middle + 1, end] 区间合并
void merge(vector<int> arr, int start, int end) 
{
	int end1 = (start + end) / 2;
	int start2 = end1 + 1;
	// 用来遍历数组的指针
	int index1 = start;
	int index2 = start2;
	while (index1 <= end1 && index2 <= end) {
		if (arr[index1] <= arr[index2]) {
			index1++;
		}
		else {
			// 右边区域的这个数字比左边区域的数字小,于是它站了起来
			int value = arr[index2];
			int index = index2;
			// 前面的数字不断地后移
			while (index > index1) {
				arr[index] = arr[index - 1];
				index--;
			}
			// 这个数字坐到 index1 所在的位置上
			arr[index] = value;
			// 更新所有下标,使其前进一格
			index1++;
			index2++;
			end1++;
		}
	}
}

// 对 arr 的 [start, end] 区间归并排序
void mergeSort(vector<int> arr, int start, int end)
{
	// 只剩下一个数字,停止拆分
	if (start == end) return;
	int middle = (start + end) / 2;
	// 拆分左边区域
	mergeSort(arr, start, middle);
	// 拆分右边区域
	mergeSort(arr, middle + 1, end);
	// 合并左右区域
	merge(arr, start, end);
}


void mergeSort(vector<int> arr)
{
	if (arr.size() == 0) return;
	mergeSort(arr, 0, arr.size() - 1);
}

实现二


void exchange(vector<int> arr, int i, int j)
{
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

// 将 arr 的 [start, middle] 和 [middle + 1, end] 区间合并
void merge(vector<int> arr, int start, int end)
{
	int end1 = (start + end) / 2;
	int start2 = end1 + 1;
	// 用来遍历数组的指针
	int index1 = start;
	while (index1 <= end1 && start2 <= end) {
		if (arr[index1] > arr[start2]) {
			// 将 index1 和 start2 下标的数字交换
			exchange(arr, index1, start2);
			if (start2 != end) {
				// 调整交换到 start2 上的这个数字的位置,使右边区域继续保持有序
				int value = arr[start2];
				int index = start2;
				// 右边区域比 arr[start2] 小的数字不断前移
				while (index < end && arr[index + 1] < value) {
					arr[index] = arr[index + 1];
					index++;
				}
				// 交换到右边区域的这个数字找到了自己合适的位置,坐下
				arr[index] = value;
			}
		}
		index1++;
	}
}


// 对 arr 的 [start, end] 区间归并排序
void mergeSort(vector<int> arr, int start, int end)
{
	// 只剩下一个数字,停止拆分
	if (start == end) return;
	int middle = (start + end) / 2;
	// 拆分左边区域
	mergeSort(arr, start, middle);
	// 拆分右边区域
	mergeSort(arr, middle + 1, end);
	// 合并左右区域
	merge(arr, start, end);
}


void mergeSort(vector<int> arr) {
	if (arr.size() == 0) return;
	mergeSort(arr, 0, arr.size() - 1);
}

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

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

相关文章

Pytorch从零开始实战04

Pytorch从零开始实战——猴痘病识别 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——猴痘病识别环境准备数据集模型选择模型训练数据可视化其他模型图片预测 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytor…

mysql用事务实现更新数据

前言&#xff1a;在手动批量更新正式环境数据库时&#xff0c;建议使用事物进行更新&#xff0c;避免更错数据&#xff0c;造成不必要的麻烦。 现表中有三条数据&#xff0c;使用事物批量将name字段为mgx&#xff0c;phone字段为17837107346&#xff0c;所有数据中的address字段…

华为云云耀云服务器L实例评测|服务器反挖矿防护指南

前言 本文为华为云云耀云服务器L实例测评文章&#xff0c;测评内容是 云耀云服务器L实例 反挖矿防护指南 系统配置&#xff1a;2核2G 3M CentOS7.9 之前的文章中『一文教你如何防御数据库恶意攻击』&#xff0c;我们讲到黑客如何通过攻击数据库来获取权限&#xff0c;以及我们…

别再纠结线程池池大小、线程数量了,哪有什么固定公式 | 京东云技术团队

可能很多人都看到过一个线程数设置的理论&#xff1a; CPU 密集型的程序 - 核心数 1 I/O 密集型的程序 - 核心数 * 2 不会吧&#xff0c;不会吧&#xff0c;真的有人按照这个理论规划线程数&#xff1f; 线程数和CPU利用率的小测试 抛开一些操作系统&#xff0c;计算机原…

C++数据结构X篇_14_二叉树的递归遍历(先序遍历、中序遍历、后续遍历方法介绍;举例;代码实现)

我们知道数据的存储结构分为线性与非线性。线性就是1对1的结构&#xff0c;像栈与队列都属于线性结构。那什么是非线性的结构呢&#xff1f; 非线性即1对n的结构这更符合常规情况&#xff0c;线性结构本质上属于非线性结构中的一种特殊形式&#xff0c;像树就属于非线性结构。但…

iOS 17 Simulator Failed with HTTP status 400:bad request

升级 xcode 15 要 ios17 的 sdk 才能运行&#xff0c;但是更新这个 sdk 400 错误了 解决方案&#xff1a; 直接去官网下载开发者后台下载dmg文件&#xff0c;使用命令行快速安装即可 https://developer.apple.com/documentation/xcode/installing-additional-simulator-runti…

Anaconda和Pycharm详细安装 配置教程

Anaconda&#xff1a;是一个开源的Python发行版本&#xff0c;其中包含了conda、Python等180多个科学包及其依赖项。【Anaconda下载】 PyCharm&#xff1a;PyCharm是一种Python IDE&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。【PyCharm下载】…

功能强大的PostgreSQL没有MySQL流行的10个原因,你知道几个?

以下内容是根据玖章算术CEO叶正盛在「3306π 数据库朋友圈」技术演讲整理。文末附完整的PPT下载链接&#xff01; MySQL与PostgreSQL都是非常优秀并且非常成功的数据库&#xff0c;PostgreSQL的功能比MySQL强大&#xff0c;但是依然没有MySQL流行&#xff0c;作者从产品功能、…

Vue3中的computed函数详解

计算属性是Vue中常用的一种方式&#xff0c;主要用于在模板中放置逻辑计算&#xff0c;方便开发者进行数据操作和展示。在Vue3中&#xff0c;计算属性依然是非常重要的一种功能&#xff0c;而computed函数则更加的方便计算属性的使用。本文将对Vue3中的computed函数进行详细的介…

terraform简单的开始-vpc cvm创建

从网络开始 从创建VPC开始 复用前面的main.tf的代码&#xff1a; terraform {required_providers {tencentcloud {source "tencentcloudstack/tencentcloud"version "1.81.25"}} } variable "region" {description "腾讯云地域"…

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二)

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二) 上一次和大家分享了组态相关的重要内容,具体可以参考以下链接中的内容: 西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(一) 本次继续和大家分享关于安全PLC基础编程的相关内容: 如下图所示,在左侧的…

开通经营收款码要手续费吗

我们都知道&#xff0c;目前市场上的支付宝或者微信商户收款&#xff0c;无论是线上收款还是实体店收款&#xff0c;一般都采用0.6%的收款费率&#xff0c;1万元就是60元。 其实这不低的。 大多数线下实体店商家可能使用的聚合支付码可能是0.38%&#xff0c;1万元是38。 虽然不…

21天学会C++:Day12----初始化列表

CSDN的uu们&#xff0c;大家好。这里是C入门的第十一讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 初始化列表 1.1 引入 1.2 初始化列表 1.3 初始化列表的注意事项 1.…

字符集(ASCII、GBK、Unicode、UTF-8)

1、字符集基础知识 计算机底层不可以直接存储字符的。计算机中底层只能存储二进制&#xff08;0、1&#xff09;二进制是可以转换成十进制的结论&#xff1a;计算机底层可以表示十进制编号。计算机可以给人类字符进行编号存储&#xff0c;这套编号规则就是字符集。 2、ASCII字符…

如何像微信一样扫码自由?

https://github.com/devilsen/CZXing 我在使用zxing的总是想扫码的时候怎么才能够快速校准&#xff0c;多个二维码扫描的时候怎么才能指定二维码呢。于是我在Github上找到了CZxing这个控件。在使用的时候发现了有些小问题。 扫码结果没有回调。 回调没有反应&#xff1b;是因…

二维码智慧门牌管理系统:提升城市管理效率与服务水平

文章目录 前言一、系统原理及特点二、系统的优势与应用 前言 在当今快速发展的信息化时代&#xff0c;如何有效地管理城市地址信息成为了各大城市面临的重要问题。传统的门牌管理系统已经无法满足现代城市的需求&#xff0c;而二维码智慧门牌管理系统作为全新的解决方案&#…

数据库开发-MySQL

数据库设计-DDL 下面我们就正式的进入到SQL语句的学习&#xff0c;在学习之前先给大家介绍一下我们要开发一个项目&#xff0c;整个开发流程是什么样的&#xff0c;以及在流程当中哪些环节会涉及到数据库。 项目开发流程 需求文档&#xff1a; 在我们开发一个项目或者项目当中…

Linux文件内容显示练习

1.新建2个文件b1.txt b2.txt ,使用vim打开b1.txt 输入“Hello World”字符串,将b1.txt硬链接到b2.txt 查看2个文件的硬连接数 [rootserver ~]# vim b1.txt [rootserver ~]# ln b1.txt b2.txt #建立硬链接 [rootserver ~]# stat b2.txt [rootserver ~]# stat b1.txt [r…

现货黄金的价格如何变动

现货黄金每天的交易时间很长&#xff0c;价格几乎全天24小时都处于波动之中&#xff0c;由于受到各种政治、经济因素的影响&#xff0c;价格波动有时可以来得十分迅猛&#xff0c;在一小时就可以波动二、三十美元&#xff0c;但有时却可以连续几天都维持在数美元的区间内波动。…

《使用 sCrypt 构建井字游戏》课程上线

《使用 sCrypt 构建井字游戏》课程上线 Learn sCrypt。Learn sCrypt 是一个交互式学习网站&#xff0c;旨在帮助开发者更快、更轻松地学习和掌握比特币智能合约开发语言 sCrypt。 井字游戏非常简单&#xff0c;就是使用两个玩家(分别是 Alice 和 Bob)的比特币地址初始化合约&a…