归并排序 图解 递归 + 非递归 + 笔记

前置知识:讲解019-算法笔试中处理输入和输出,讲解020-递归和master公式

  • (1)左部分排好序,右部分排好序,利用merge过程让左右整体有序
  • (2)merge过程:谁小拷贝谁,直到左右两部分所有的数字耗尽
  • (3)递归实现和非递归实现
  • (4)时间复杂度O(n*logn)
  • (5)需要辅助数组,所以额外空间复杂度O(n)
  • (6)归并排序为什么比O(n^2)的排序快?因为比较行为没有浪费!
  • (7)利用归并排序的便利性可以解决很多问题,例如归并分治

注意:有些资料说可以用原地归并排序,把额外空间复杂度变成O(1),不要浪费时间去学。因为原地归并排序确实可以省空间,但是会把复杂度变成O(n^2)

  • 对这个数组arr=[6,4,2,3,9,4] ,进行归并排序 

  • 挑其中一步来演示: 把[2,4,6]和[3,4,9]合并(merge)

最后再刷回原数组 

void merge(int left, int mid, int right) {
	int i = left;
	int a = left;
	int b = mid + 1;
	while (a <= mid && b <= right) {
		help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
	}
	// 左侧指针,右侧指针,必有一个越界,另一个不越界
	while (a <= mid) {
		help[i++] = arr[a++];
	}
	while (b <= right) {
		help[i++] = arr[b++];
	}
	for (i = left; i <= right; i++) { // 把 help 里面的数据重新刷回到原数组arr
		arr[i] = help[i];
	}
}

(1)归并排序递归版

// 递归方法
void mergeSort(int left, int right) {
	if (left == right) return;
	int mid = (left + right) / 2;
	mergeSort(left, mid);
	mergeSort(mid + 1, right);
	merge(left, mid, right);
}

(2)归并排序非递归版

void mergeSort2() {
	// 一共发生O(logn)次
	for (int left, mid, right, step = 1; step < n; step <<= 1) {
		// 内部分组merge,时间复杂度:O(n)
		left = 0;
		while (left < n) {
			mid = left + step - 1;
			if (mid + 1 >= n) {
				// 已经没有右侧了
				break;
			}
			// 有右侧,求右侧的右边界
			right = min(left + (step << 1) - 1, n - 1);
			// left ... mid mid+1 ... right
			//								left ... mid mid+1 ... right
			//															 left ... mid mid+1 ... right
			merge(left, mid, right);
			left = right + 1;
		}
	}	
}

完整代码:

/*
* 前置知识:讲解019-算法笔试中处理输入和输出,讲解020-递归和master公式
	(1)左部分排好序,右部分排好序,利用merge过程让左右整体有序
	(2)merge过程:谁小拷贝谁,直到左右两部分所有的数字耗尽
	(3)递归实现和非递归实现
	(4)时间复杂度O(n*logn)
	(5)需要辅助数组,所以额外空间复杂度O(n)
	(6)归并排序为什么比O(n^2)的排序快?因为比较行为没有浪费!
	(7)利用归并排序的便利性可以解决和诺问题 - 归并分治 - 下节课
	注意:
	有些资料说可以用原地归并排序,把额外空间复杂度变成O(1),不要浪费时间去学
	因为原地归并排序确实可以省空间,但是会把复杂度变成O(n^2)
	有关排序更多的概念,注意点,闭坑指南,将在后序课程继续
*/
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#include <malloc.h>
#define MAXI 501
int arr[] = { 6,4,2,3,9,4 };
int n = sizeof(arr) / sizeof(arr[0]);
int help[MAXI];

void merge(int left, int mid, int right) {
	int i = left;
	int a = left;
	int b = mid + 1;
	while (a <= mid && b <= right) {
		help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
	}
	// 左侧指针,右侧指针,必有一个越界,另一个不越界
	while (a <= mid) {
		help[i++] = arr[a++];
	}
	while (b <= right) {
		help[i++] = arr[b++];
	}
	for (i = left; i <= right; i++) { // 把 help 里面的数据重新刷回到原数组arr
		arr[i] = help[i];
	}
}

/*
	归并排序递归版
	假设left...right一共 n 个数
	T(n) = 2 * T(n/2) + O(n)
	a = 2,b = 2,c = 1
	根据master公式,时间复杂度:O(n * logn)
	空间复杂度:O(n)
*/
// 递归方法
void mergeSort(int left, int right) {
	if (left == right) return;
	int mid = (left + right) / 2;
	mergeSort(left, mid);
	mergeSort(mid + 1, right);
	merge(left, mid, right);
}

// 归并排序非递归版
// 时间复杂度:O(n * logn)
// 空间复杂度:O(n)
void mergeSort2() {
	// 一共发生O(logn)次
	for (int left, mid, right, step = 1; step < n; step <<= 1) {
		// 内部分组merge,时间复杂度:O(n)
		left = 0;
		while (left < n) {
			mid = left + step - 1;
			if (mid + 1 >= n) {
				// 已经没有右侧了
				break;
			}
			// 有右侧,求右侧的右边界
			right = min(left + (step << 1) - 1, n - 1);
			// left ... mid mid+1 ... right
			//								left ... mid mid+1 ... right
			//															 left ... mid mid+1 ... right
			merge(left, mid, right);
			left = right + 1;
		}
	}	
}

int main() {
	//mergeSort(0, n - 1);
	mergeSort2();
	for (int i = 0; i < n; i++) {
		cout << " " << arr[i] << " " << endl;
	}
	system("pause");
	return 0;
}

完整图:

参考和推荐视频:

算法讲解021【必备】归并排序_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1wu411p7r7/?spm_id_from=333.999.list.card_archive.click&vd_source=a934d7fc6f47698a29dac90a922ba5a3

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NFT合约部署

部署合约&#xff1a; 1.web3 NFT合约部署工具 https://remix.ethereum.org/ 2.tron NFT合约部署工具 https://www.tronide.io/ 3.部署 web3 ERC721代码&#xff1a; // SPDX-License-Identifier: MIT pragma solidity ^0.8.2;import "openzeppelin/contracts/token/ERC7…

【java:牛客每日三十题总结-4】

java:牛客每日三十题总结 总结如下 总结如下 集合相关知识点 元素是否排序和插入顺序无关&#xff0c;取决与集合实现是否考虑了传入对象的java.lang.Comparable接口抽象类和接口相关知识 只能说越来越抽象了 java线程通信的方式 在Java中&#xff0c;常用的线程通信方式有两…

Leetcode_3:Pow(x,n)

题目描述&#xff1a; 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000示例 2&#xff1a; 输入&#xff1a;x 2.10000, n 3 输出&#xff1a;9.26100示例 3&#xff1a; 输入&…

Android 多点触控

三种类型 :接力型 /配合型 /单独型 单点触控 package com.example.myapplication.viewimport android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.util.AttributeSet import android.view.MotionEvent import android.vi…

剑指offer(C++)-JZ21:调整数组顺序使奇数位于偶数前面(一)(算法-其他)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 输入一个长度为 n 整数数组&#xff0c;实现一个函数来调整该数组中数字的顺序&#xff0c;使得所有的奇数…

d3.js

D3&#xff1a;Data-Driven Documents • 通过D3提供的接口来基于数据操控文档的各个图元。 标题对于D3(本讲解)最为重要的标签&#xff0c;主要操作的对象(画布) HTML - 导入D3.js D3.js作为JavaScript的外库&#xff0c;必须先将其导入&#xff0c;如&#xff1a; Python的…

Android 图层列表 、 LayerDrawable 、 layer-list \ 改变 seekbar thumb 滑块 的颜色

android 官网 &#xff1a; 图层列表 LayerDrawable / layer-list LayerDrawable 是管理其他可绘制对象数组的可绘制对象。列表中的每个可绘制对象均按照列表顺序绘制。列表中的最后一个可绘制对象绘于顶部。 每个可绘制对象均由单个 <layer-list> 元素内的 <item>…

计算机毕业设计:基于python机器学习的全国气象数据采集预测可视化系统 预测模型+爬虫(包含文档+源码+部署教程)

[毕业设计]2023-2024年最新最全计算机专业毕设选题推荐汇总 感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;希望帮助更多的人 。 1、摘 要 随着气候变化的不断加剧&#xff0c;气象数据的准确性…

方太集团合同档案管理平台,让数字化成果深度利用、可查可验

数字经济大背景下&#xff0c;方太集团积极拥抱企业数字化转型&#xff0c;推动合同档案业务管理数字化&#xff0c;助力业务档案高效融合&#xff0c;助力企业创新科技发展。 方太集团&#xff08;以下简称“方太”&#xff09;创建于1996年。作为一家以智能厨电为核心业务的…

美国材料与试验协会ASTM发布新版玩具安全标准 ASTM F963-23

美国材料与试验协会ASTM发布新版玩具安全标准 ASTM F963-23 2023年10月13日&#xff0c;美国材料与试验协会&#xff08;ASTM&#xff09;发布了新版玩具安全标准ASTM F963-23 ​根据CPSIA的规定&#xff0c;当ASTM将ASTM F963的拟定修订意见通知CPSC时&#xff0c;若CPSC认为…

SpringDataJpa(三)

七、Specifications动态查询 有时我们在查询某个实体的时候&#xff0c;给定的条件是不固定的&#xff0c;这时就需要动态构建相应的查询语句&#xff0c;在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象。 import …

电动汽车多时段动态充电价格及网损策略研究

摘要&#xff1a;电动汽车以无序充电方式接入配电网时与网内基础用电负荷叠加&#xff0c;会形成峰上加峰的现象&#xff0c;不利于配电网的稳定运行。针对上述问题&#xff0c;首先对私家车充电负荷进行建模&#xff0c;采用蒙特卡罗抽样模拟电动汽车无序行为下的充电负荷曲线…

【PostgreSql高阶语法 】1、CASE WHEN THEN END用法

目录 1. 基础描述2. 用法举例2.1 基础使用2.1.1 方式12.1.2 方式 2 2.2 进行分组2.3 分组练习举例 1. 基础描述 目的&#xff1a;在SQL语句中添加判断条件&#xff0c;就要用到CASE WHEN THEN END用法&#xff1a;类似于java里面的switch语句&#xff0c;一组CASE WHEN THEN E…

Harmony 应用开发的知识储备

Harmony 应用开发的知识储备 前言正文一、DevEco Studio版本二、手机版本① 环境变量 三、API版本四、开发语言五、运行调试 前言 这里先说明一点&#xff0c;如果你对Android应用开发很熟悉&#xff0c;那么做Harmony应用开发也可以驾轻就熟&#xff0c;只不过在此之前你需要知…

Gated Context Aggregation Network for Image Dehazing and Deraining(GCANet)

1 总体概述 GCANet是端到端去雾的一篇代表性的文章&#xff0c;它摒弃以往使用手工设计的先验以及大气散射模型的使用&#xff0c;直接通过原始有雾图像估计出无雾图像J与有雾图像I之间的残差&#xff0c;图像恢复阶段直接使用网络输出的残差与输入有雾图像I之间的加和完成去雾…

MyBatis-plus最详细的入门使用教程来了

1.概述 MyBatis-Plus &#xff08;简称 MP&#xff0c;下文就使用简称啦&#xff09;是一个 MyBatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。官网地址&#xff1a;https://baomidou.com/ 有以下特性&#xff1a; 无…

modbus-TCP协议详解

modbus-TCP协议详解 1996年施耐德公司推出基于以太网TCP/IP的modbus协议&#xff1a;modbus-TCP。 MODBUS-TCP使MODBUS-RTU协议运行于以太网&#xff0c;MODBUS-TCP使用TCP/IP以太网在站点间传送MODBUS报文&#xff0c;MODBUS-TCP结合了以太网物理网络和网络标准TCP/IP以及以…

春江天玺89㎡三室两厅,现代轻奢丨不止风格更是一种生活态度。福州中宅装饰,福州装修

空间在格局上并没做太多改动&#xff0c;在满足基本的室内功能基础上&#xff0c;用相对简洁的手法来做立面整体的统筹与演绎&#xff0c;在提亮整个空间感的情况下&#xff0c;进行合理的动线分区&#xff0c;提高空间利用率&#xff0c;成为本案的设计要点。 Part 1 在客厅的…

JVM中jhat虚拟机堆转储快照分析工具

jhat虚拟机堆转储快照分析工具 1、jhat jhat也是jdk内置的工具之一。主要是用来分析java堆的命令&#xff0c;可以将堆中的对象以html的形式显示出来&#xff0c;包括对 象的数量&#xff0c;大小等等&#xff0c;并支持对象查询语言。 使用jmap等方法生成java的堆文件后&a…

HHDESK端口转发监控服务

端口转发是一种网络技术&#xff0c;用于将外部网络请求转发到内部网络中的特定设备或服务。它允许通过公共网络访问内部网络中的资源&#xff0c;提供了灵活性和便利性。 传统的端口转发方式是通过配置路由器的端口映射&#xff0c;但这需要具备网络知识和一定的技术操作&…