八大排序——归并排序

目录

1.基本思想

2.动态图

3.分解的时候我们可以使用递归的方式进行

代码解释

1. main 方法

2. mergeSort 方法

3. merge 方法

示例运行过程

初始数组

每轮排序后的数组

代码总结


合并两个有序序列

1.基本思想

归并排序就是递归得将原始数组递归对半分隔,直到不能再分(只剩下一个元素)后,开始从最小的数组向上归并排序。

  1. 将一个数组拆分为两个,从中间点拆开,通过递归操作来实现一层一层拆分。

  2. 从左右数组中选择小的元素放入到临时空间,并移动下标到下一位置。

  3. 重复步骤2直到某一下标达到尾部。

  4. 将另一序列剩下的所有元素依次放入临时空间。

  5. 将临时空间的数据依次放入原数据数组。

2.动态图

下边是动态图

3.分解的时候我们可以使用递归的方式进行

首先我们可以先定义三个变量,

数组的头部位置可以定义为 low,数组的尾部可以定义为high

因为每次分解都是要折半,所以我们可以定义数组的中间是 mid,如下图所示

我们从上图当中可以看到,我们每一次递归,都是将原来的mid当成新的high,一直到low = high的时候我们就已经可以说明我们将一个数据分离了出来。所以我们可以写以下代码来表示分。

    public static void mergeSort(int[] a, int low, int high) {
        //首先判断 low 和 high是否指向一个地方
        if(low >= high) {
            return;
        }
        int mid = (low + high)/2;
        //先递归左边
        mergeSort(a, low, mid);
        //在递归右边
        mergeSort(a, mid+1, high);

    }

首先我们可以先递归左边,直到我们讲第一个值分离出去,然后再回溯,分离他右边的那个,如下如所以:

当递归完成之后我们该开始合并了

首先我们需要先弄懂一个地方就是合并是在哪里开始的。

首先我们要知道我们第一次回溯之后,将第二个元素分离了出来,第二个元素分离完成之后,也会回溯回去,那么此一次合并就是 值 6 和 5的合并。

下边我们为了演示选择了 5,6 , 1 , 3的合并过程

首先我们需要弄清楚,我们这里所谓的分离其实是概念意义上的,在我们的数组结构上其实并没有分离,而且由于回溯的原因 5,6 , 1 , 3是其实和上边是对应的关系,如图所示

下边我们来一步一步的展示整个合并的过程,

首先我么可以定义两个指针,s1和s2,然后在定义一个新的临时数组来存储数据

我们将指针s1的范围锁定在 s1<=min ,将指针s2的范围锁定在s2<=high,我们可以比较s1和s2当前指向的值的大小,将小的一方放入到临时数组当中去,直到s1或s2一方指向为空,那么就可以将另一方全部放入到临时数组当中去。然后将临时的代码在放回数组

代码如下:

代码

public class ShellSort {
	
	public static void main(String[] args) {
        int a[] = {6,5,3,1,8,7,2,4};
        mergeSort(a, 0, a.length - 1);
        System.out.println("排序结果:" + Arrays.toString(a));
	}
	//分
	public static void mergeSort(int[] a, int low, int high) {
		//首先判断 low 和 high是否指向一个地方
           // 正常情况下就是 == 
		if(low == high) {
			return;
		}
		int mid = (low + high)/2;
		//先递归左边
		mergeSort(a, low, mid);
		//在递归右边
		mergeSort(a, mid+1, high);
		//合并
		merge(a,low,mid,high);
		System.out.println(Arrays.toString(a));
    }
	//合并
	public static void merge(int[] a, int low, int mid, int high) {
		//定义第一个段的开始
		int s1 = low;
		//定义第二个段的开始
		int s2 = mid+1;
		//定义临时数组
		int[] temp = new int[high-low+1];
		int i = 0;//定义临时数组的下标
		//判断大小将数组放入到临时数组当中去
		while(s1<=mid && s2<=high) {
			if(a[s1] <= a[s2]) {
				temp[i++] = a[s1++];
			}else {
				temp[i++] = a[s2++];
			}
		}
		//判断s1当中是否有数据,如果有将其全部拷贝到临死数组当中去
		while (s1 <= mid) {
			temp[i++] = a[s1++];
			
		}
		
		//判断s1当中是否有数据,如果有将其全部拷贝到临死数组当中去
		while (s2 <= high) {
			temp[i++] = a[s2++];
			
		}
		
		//将临时数组当中的代码放回原数组
		for (int j = 0; j < temp.length; j++) {
			a[j+low] = temp[j];
		}
		
	}
}

代码解释

1. main 方法

public static void main(String[] args) {
    int a[] = {6, 5, 3, 1, 8, 7, 2, 4};
    mergeSort(a, 0, a.length - 1);
    System.out.println("排序结果:" + Arrays.toString(a));
}
  • 功能:程序的入口。

  • 逻辑

    • 定义了一个未排序的整数数组 a

    • 调用 mergeSort 方法对数组进行排序。

    • 打印排序后的数组。

2. mergeSort 方法

public static void mergeSort(int[] a, int low, int high) {
    // 首先判断 low 和 high 是否指向一个地方
    if (low == high) {
        return;
    }
    int mid = (low + high) / 2;
    // 先递归左边
    mergeSort(a, low, mid);
    // 再递归右边
    mergeSort(a, mid + 1, high);
    // 合并
    merge(a, low, mid, high);
    System.out.println(Arrays.toString(a));
}

  • 功能:实现归并排序的分治逻辑。

  • 逻辑

    1. 递归终止条件

      • 如果 low == high,说明当前子数组只有一个元素,无需排序,直接返回。

    2. 计算中间位置

      • mid = (low + high) / 2,将数组分成两个子数组。

    3. 递归排序左半部分

      • 调用 mergeSort(a, low, mid),对左半部分进行排序。

    4. 递归排序右半部分

      • 调用 mergeSort(a, mid + 1, high),对右半部分进行排序。

    5. 合并两个有序子数组

      • 调用 merge(a, low, mid, high),将两个有序子数组合并成一个有序数组。

    6. 打印每轮排序后的数组

      • 每轮排序后,打印当前数组的状态。

3. merge 方法

public static void merge(int[] a, int low, int mid, int high) {
    // 定义第一个段的开始
    int s1 = low;
    // 定义第二个段的开始
    int s2 = mid + 1;
    // 定义临时数组
    int[] temp = new int[high - low + 1];
    int i = 0; // 定义临时数组的下标
    // 判断大小将数组放入到临时数组当中去
    while (s1 <= mid && s2 <= high) {
        if (a[s1] <= a[s2]) {
            temp[i++] = a[s1++];
        } else {
            temp[i++] = a[s2++];
        }
    }
    // 判断 s1 当中是否有数据,如果有将其全部拷贝到临时数组当中去
    while (s1 <= mid) {
        temp[i++] = a[s1++];
    }
    // 判断 s2 当中是否有数据,如果有将其全部拷贝到临时数组当中去
    while (s2 <= high) {
        temp[i++] = a[s2++];
    }
    // 将临时数组当中的数据放回原数组
    for (int j = 0; j < temp.length; j++) {
        a[j + low] = temp[j];
    }
}

  • 功能:合并两个有序子数组。

  • 逻辑

    1. 初始化指针

      • s1 指向左半部分的起始位置(low)。

      • s2 指向右半部分的起始位置(mid + 1)。

    2. 定义临时数组

      • temp 用于存储合并后的有序数组。

    3. 比较并合并

      • 比较 a[s1] 和 a[s2],将较小的元素放入 temp 中。

      • 移动相应的指针(s1 或 s2)。

    4. 处理剩余元素

      • 如果左半部分还有剩余元素,将其全部拷贝到 temp 中。

      • 如果右半部分还有剩余元素,将其全部拷贝到 temp 中。

    5. 将临时数组的数据拷贝回原数组

      • 将 temp 中的数据拷贝回原数组 a 的对应位置。

示例运行过程

初始数组

[6, 5, 3, 1, 8, 7, 2, 4]

每轮排序后的数组

  1. 第1轮

    • 左半部分排序:[5, 6]

    • 右半部分排序:[1, 3]

    • 合并结果:[1, 3, 5, 6, 8, 7, 2, 4]

  2. 第2轮

    • 左半部分排序:[1, 3, 5, 6]

    • 右半部分排序:[2, 4, 7, 8]

    • 合并结果:[1, 2, 3, 4, 5, 6, 7, 8]

最终排序结果

[1, 2, 3, 4, 5, 6, 7, 8]

代码总结

  • 算法:归并排序。

  • 时间复杂度:O(n log n),其中 n 是数组的长度。

  • 空间复杂度:O(n),需要额外的临时数组来存储合并结果。

  • 优点:稳定排序,时间复杂度较低,适合大规模数据。

  • 缺点:需要额外的空间。

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

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

相关文章

C++ Primer 跳转语句

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

Elasticsearch:15 年来致力于索引一切,找到重要内容

作者&#xff1a;来自 Elastic Shay Banon 及 Philipp Krenn Elasticsearch 刚刚 15 岁了&#xff01;回顾过去 15 年的索引和搜索&#xff0c;并展望未来 15 年的相关内容。 Elasticsearch 刚刚成立 15 周年。一切始于 2010 年 2 月的一篇公告博客文章&#xff08;带有标志性的…

后稀缺社会的经济模型:当技术突破资源边界时的范式革命

文章目录 引言:走出马尔萨斯陷阱一、技术基础:构建后稀缺社会的四大支柱1.1 自动化生产系统:边际成本趋零的物理基础1.2 能源基础设施:聚变-光伏-储能的黄金三角二、经济模型转变:从稀缺范式到丰裕范式2.1 传统经济模型的失效2.2 新价值方程的涌现三、后稀缺经济的三层架构…

macOS部署DeepSeek-r1

好奇&#xff0c;跟着网友们的操作试了一下 网上方案很多&#xff0c;主要参考的是这篇 DeepSeek 接入 PyCharm&#xff0c;轻松助力编程_pycharm deepseek-CSDN博客 方案是&#xff1a;PyCharm CodeGPT插件 DeepSeek-r1:1.5b 假设已经安装好了PyCharm PyCharm: the Pyth…

记录-rtsp 链接中账号密码包含有@的导致解析失败

问题&#xff1a; 在使用librtsp开源库的时候发现&#xff0c;当输入的rtsp流包含有多个的时候 (比如账号密码中包含,rtsp://admin:Pssw0rd192.168.31.xxx/Streaming/Channels/101)&#xff0c;会导致拉流失败。 问题处理&#xff1a; 一、这是因为librtsp中只对一个做了解析…

纪念日倒数日项目的实现-【纪念时刻-时光集】

纪念日/倒数日项目的实现## 一个练手的小项目&#xff0c;uniappnodemysql七牛云。 在如今快节奏的生活里&#xff0c;大家都忙忙碌碌&#xff0c;那些具有特殊意义的日子一不小心就容易被遗忘。今天&#xff0c;想给各位分享一个“纪念日”项目。 【纪念时刻-时光集】 一…

JDK 14,15,17的一些新特性(部分常用)

1&#xff1a;instanceof&#xff08;后&#xff0c;使用不再需要墙转&#xff09; 2&#xff1a;switch语句增强 1&#xff1a;支持lmbda&#xff0c;自动防击穿&#xff0c;有返回值 2&#xff1a;支持case多个值&#xff0c;复杂逻辑结果支持yield返回 3&#xff1a;字符串…

Linux学习笔记之进程

进程 进程的定义 进程是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配的基本单位&#xff0c;也是操作系统结构的基础。   例如当QQ程序运行的时候&#xff0c;计算机会先从磁盘读取QQ程序到内存&#xff0c;然后OS管理这个程序&#xff0c;…

泛型 类 接口 方法 通配符

泛型 泛型类 what: 类型参数化 why use&#xff1a; 1. 输出时候是object类型 而不是真正类型转化麻烦 import java.util.ArrayList; import java.util.List;public class ObjectExample {public static void main(String[] args) {List<Object> list new ArrayLi…

打穿内网三重奏-红日7

靶机下载地址&#xff1a; 漏洞详情 (qiyuanxuetang.net) 攻击链路&#xff1a; DMZ区IP段为192.168.11.1/24 第二层网络环境IP段为192.168.52.1/24 第三层网络环境IP段为192.168.93.1/24 这里DMZ和攻击者我用的是192.168.11.1 这个网段&#xff0c;其他不变 这里我加了两张…

windows 10安装sqlyog详细步骤

sqlyog下载链接&#xff1a; 链接: https://pan.baidu.com/s/1D_iRna8V90omfHsKHyeBtg 提取码: bqht 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 1. 下载完以后解压&#xff0c;双击SQLyog-12.0.9-0.x64 2. 如下图&#xff0c;选择Ok 3 . 如图&#xff0c;点…

OpenAI 放王炸,将发布整合多项技术的 GPT-5,并免费无限使用,该模型有哪些技术亮点

对于 ChatGPT 的免费用户&#xff0c;将可以无限制地访问 GPT-5&#xff0c;但仅限于标准的智能级别。该级别会设定滥用限制&#xff0c;以防止不当使用(意思就是你得付费嘛)。 OpenAI CEO Sam Altman 今天在 X 上透露了 GPT-4.5 和 GPT-5 的最新发展计划。 OpenAI 将发布代…

深度学习框架探秘|TensorFlow vs PyTorch:AI 框架的巅峰对决

在深度学习框架中&#xff0c;TensorFlow 和 PyTorch 无疑是两大明星框架。前面两篇文章我们分别介绍了 TensorFlow&#xff08;点击查看&#xff09; 和 PyTorch&#xff08;点击查看&#xff09;。它们引领着 AI 开发的潮流&#xff0c;吸引着无数开发者投身其中。但这两大框…

UEFI PI PEI(2. PEI Services and Table)

PEI Services 1. PEI Services Table介绍 PEI Foundation建立了一个名为PEI Services Table的系统表&#xff0c;该表对系统中的所有Pre-EFI初始化模块&#xff08;PEIMs&#xff09;可见。 PEI Foundation在系统初始化时所需要的功能、命令或其他能力&#xff0c;会被抽象然…

2025常用的SEO工具有哪些?

在互联网时代&#xff0c;如何让自己的网站或内容脱颖而出&#xff0c;成为许多企业和个人站长们最关注的问题。而在这个过程中&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;作为一种有效的提升网站曝光度和吸引流量的手段&#xff0c;已经成为了网站运营的核心之一。对…

Winform自定义控件与案例 - 一款功能丰富的自定义文本按钮(TextButton)控件

深入解析:TextButton —— 一款功能丰富的自定义文本按钮控件 在 WinForms 开发中,标准的按钮控件虽然能够满足基本需求,但在现代 UI 设计中显得过于简单。为了提升用户体验和界面美观度,我们开发了 TextButton,一个基于 WWControlBase 的自定义文本按钮控件。它不仅支持…

安卓自我学习

纯粹三分钟热度, 这里 我百度查询资料, 按步骤创建了emtry 项目, 这里选择apk 12 , java 别问我kotlin, 啥都不会, …… 至于是叫小林学习,最初是在csdn 那里看到小林博主的文章, 激起一点点热度, 想学习一下 找了一圈 我先右上角选择 trouble ,, ,,看图1-1 图1-1 点运行…

【SpringBoot3.x+】slf4j-log4j12依赖引入打印日志报错的两种解决方法

最开始引入了1.7.5版本的slf4j-log4j依赖包&#xff0c;但是控制台不报错也不显示日志 在https://mvnrepository.com/找到最新的2.0.16版本之后出现报错&#xff1a; 进入提示的slf4j网站中可以找到从2.0.0版本开始&#xff0c;slf4j-log4j已经被slf4j-reload4j取代&#xff1…

LabVIEW袜品压力测试系统

开发了一种基于LabVIEW开发的袜品压力测试系统。该系统利用LabVIEW并结合灵敏的传感器和高精度的处理模块&#xff0c;实现了对袜品压力的精确测量和分析。系统不同于传统的服装压力测试方法&#xff0c;为研究和评价袜子的舒适性提供了新的测试手段。 ​ 项目背景 该系统的…

【Unity Shader编程】之顶点着色器

来一张AI提供的资料 一&#xff0c;坐标空间转换 空间转换中&#xff0c;一般有五个空间转换&#xff0c;模型空间→世界空间→视图空间→裁剪空间→NDC空间&#xff08;其次坐标空间&#xff0c;执行其次坐标后的空间)→屏幕空间 核心原则 1&#xff0c;数据依赖原则 当逻…