当前位置: 首页 > news >正文

中邮通建设咨询有限公司官方网站/在线培训考试系统

中邮通建设咨询有限公司官方网站,在线培训考试系统,清远市seo网站设计联系方式,水果网站怎么做归并排序 算法思想 将数组元素不断地拆分,直到每一组中只包含一个元素,单个元素天然有序。之后用归并的方式收集跨组的元素,最终形成整个区间上有序的序列。 稳定性分析 归并排序是稳定的,拆分数组时会自然地将元素分成有先后…

归并排序

算法思想

将数组元素不断地拆分,直到每一组中只包含一个元素,单个元素天然有序。之后用归并的方式收集跨组的元素,最终形成整个区间上有序的序列。

稳定性分析

归并排序是稳定的,拆分数组时会自然地将元素分成有先后顺序的子数组,在归并的过程中如果遇到相等的值,优先收集早出现的子数组中的那个即可。

具体实现

递归

// 注意预先定义辅助数组,防止递归层数深的情况下花大量时间空间去开数组
public static int MAX_N = 50010;
public static int[] temp = new int[MAX_N];// 归并,用于将已经有序的两个数组合并成更大的有序数组
private void merge(int[] arr, int left, int mid,  int right) {int index1 = left, index2 = mid + 1, index = left;// 两个数组都有剩余元素,每次收集值较小的元素while(index1 <= mid && index2 <= right) {temp[index++] = arr[index1] <= arr[index2] ? arr[index1++] : arr[index2++];}// 其中一个数组为空,将另一个数组剩余的所有元素都添加到结果数组的末尾while(index1 <= mid) {temp[index++] = arr[index1++];}while(index2 <= right) {temp[index++] = arr[index2++];}// 结果回写到原数组System.arraycopy(temp, left, arr, left, right - left + 1);
}// 归并排序
private void mergeSort(int[] arr, int left, int right) {// 左右端点相同,数组中只有单个元素认为天然有序if (left == right) {return;}int mid = left + ((right - left) >>> 1); // 计算区间中点作为划分数组的依据// 递归地对左半边数组进行排序mergeSort(arr, left, mid);// 递归地对右半边数组进行排序mergeSort(arr, mid + 1, right);// 归并收集结果merge(arr, left, mid, right);
}

非递归

// 注意预先定义辅助数组,防止递归层数深的情况下花大量时间空间去开数组
public static int MAX_N = 50010;
public static int[] temp = new int[MAX_N];// 归并方法,用于将已经有序的两个数组合并成更大的有序数组
private void merge(int[] arr, int left, int mid,  int right) {int index1 = left, index2 = mid + 1, index = left;// 两个数组都有剩余元素,每次收集值较小的元素while(index1 <= mid && index2 <= right) {temp[index++] = arr[index1] <= arr[index2] ? arr[index1++] : arr[index2++];}// 其中一个数组为空,将另一个数组剩余的所有元素都添加到结果数组的末尾while(index1 <= mid) {temp[index++] = arr[index1++];}while(index2 <= right) {temp[index++] = arr[index2++];}// 结果回写到原数组System.arraycopy(temp, left, arr, left, right - left + 1);
}// 归并排序
private void mergeSort(int[] arr) {int n = arr.length;// 根据步长来迭代,每一轮扩大一倍for (int left, mid, right, step = 1; step < n; step <<= 1) {left = 0; // 左端点从 0 开始while (left < n) {mid = left + step - 1; // 计算区间中点的位置// 另一半区间无法构成,直接进行下一轮if (mid >= n - 1) {break;}// 数组内剩余元素不一定够填满右半边数组,右端点要根据情况来取值right = Math.min(left + (step << 1) - 1, n - 1);merge(arr, left, mid, right);// 移动指针,准备归并右半边数组left = right + 1;}}
}

归并分治

分治是一种算法思想,归并分治顾名思义就是涉及到了归并的分治策略。这部分内容其实和排序关系不大,但是作为归并应用的扩展放在一起整理比较合适的。

算法思想

如果一个问题满足两个条件,那么大概率可以使用归并分治解决:

  • 全局的结果相当于划分成两部分之后,左半边、右半边与跨左右三部分的结果的并集,也就是这个问题可以总中间拆分成子问题。
  • 如果拆分之后小范围上有序,能够使得计算跨左右的答案时更方便。

实践案例:Leetcode 493. 翻转对

递归

class Solution {// 注意预先定义辅助数组,防止递归层数深的情况下花大量时间空间去开数组public static int MAX_N = 50010;public static int[] temp = new int[MAX_N];public int reversePairs(int[] nums) {return reversePairs(nums, 0, nums.length - 1);}// 重载一个同名方法,将它改造成方便递归的形式private int reversePairs(int[] nums, int left, int right) {// 只有一个元素的情况下没有答案if(left == right) {return 0;}int mid = left + ((right - left) >>> 1);// 结果等于左半边、右半边与跨左右的结果的并集return reversePairs(nums, left, mid) + reversePairs(nums, mid + 1, right) + merge(nums, left, mid, right);}private int merge(int[] nums, int left, int mid,  int right) {int res = 0;// 当前跨小范围的情况下,更小范围内已经有序for(int i = left, j = mid + 1; i <= mid; i++) {// 确定了当前轮 j 的位置之后,这个指针不会回退,这也是提升性能的根本原因while(j <= right && (long) nums[i] > (long) 2 * nums[j]) {j++;}res += j - mid - 1;}// 常规归并流程int index1 = left, index2 = mid + 1, index = left;while(index1 <= mid && index2 <= right) {temp[index++] = nums[index1] <= nums[index2] ? nums[index1++] : nums[index2++];}while(index1 <= mid) {temp[index++] = nums[index1++];}while(index2 <= right) {temp[index++] = nums[index2++];}System.arraycopy(temp, left, nums, left, right - left + 1);return res;}
}

非递归

class Solution {// 注意预先定义辅助数组,防止递归层数深的情况下花大量时间空间去开数组public static int MAX_N = 50010;public static int[] temp = new int[MAX_N];public int reversePairs(int[] nums) {int res = 0;int n = nums.length;for (int left, mid, right, step = 1; step < n; step <<= 1) {left = 0;while (left < n) {mid = left + step - 1;if (mid >= n - 1) {break;}right = Math.min(left + (step << 1) - 1, n - 1);res += merge(nums, left, mid, right); // 累计每次归并的结果left = right + 1;}}return res;}private int merge(int[] nums, int left, int mid,  int right) {int res = 0;// 当前跨小范围的情况下,更小范围内已经有序for(int i = left, j = mid + 1; i <= mid; i++) {// 确定了当前轮 j 的位置之后,这个指针不会回退,这也是提升性能的根本原因while(j <= right && (long) nums[i] > (long) 2 * nums[j]) {j++;}res += j - mid - 1;}// 常规归并流程int index1 = left, index2 = mid + 1, index = left;while(index1 <= mid && index2 <= right) {temp[index++] = nums[index1] <= nums[index2] ? nums[index1++] : nums[index2++];}while(index1 <= mid) {temp[index++] = nums[index1++];}while(index2 <= right) {temp[index++] = nums[index2++];}System.arraycopy(temp, left, nums, left, right - left + 1);return res;}
}

梳理总结

分治是一种通过不断划分来减小问题规模,而归并是用来收集得到全局结果的方法。上面的例子所使用的都是一分为二的做法,其实每一轮可以划分成更多子问题,演变成多路归并。
正是上面这种不停划分的过程,使得无论是归并排序还是归并分治,都能有效地将暴力搜索需要 O ( N 2 ) O(N ^ 2) O(N2) 量级的方法,优化到 O ( N l o g N ) O(NlogN) O(NlogN) 这个级别。
当然,本质上来说还是空间换时间,这样的操作很明显需要 O ( N ) O(N) O(N) 量级的额外空间。

从使用上来说,归并排序一般不会成为手写排序的选择。但是归并分治则是很多问题的优秀解决方案,需要注意它的使用前提和具体实现。

后记

使用 Leetcode 912. 排序数组 进行测试,归并排序能够比较高高效地完成任务,略逊于计数排序和基数排序(不过其实题目要求使用尽可能少的额外空间,归并排序肯定不属于首选的方案)。

相关文章:

常见排序算法总结 (三) - 归并排序与归并分治

归并排序 算法思想 将数组元素不断地拆分&#xff0c;直到每一组中只包含一个元素&#xff0c;单个元素天然有序。之后用归并的方式收集跨组的元素&#xff0c;最终形成整个区间上有序的序列。 稳定性分析 归并排序是稳定的&#xff0c;拆分数组时会自然地将元素分成有先后…...

【后端开发】Go语言编程实践,Goroutines和Channels,基于共享变量的并发,反射与底层编程

【后端开发】Go语言编程实践&#xff0c;Goroutines和Channels&#xff0c;基于共享变量的并发&#xff0c;反射与底层编程 【后端开发】Go语言高级编程&#xff0c;CGO、Go汇编语言、RPC实现、Web框架实现、分布式系统 文章目录 1、并发基础, Goroutines和Channels2、基于共享…...

PyTorch 2.5.1: Bugs修复版发布

一&#xff0c;前言 在深度学习框架的不断迭代中&#xff0c;PyTorch 社区始终致力于提供更稳定、更高效的工具。最近&#xff0c;PyTorch 2.5.1 版本正式发布&#xff0c;这个版本主要针对 2.5.0 中发现的问题进行了修复&#xff0c;以提升用户体验。 二&#xff0c;PyTorch 2…...

【Android】组件化嘻嘻嘻gradle耶耶耶

文章目录 Gradle基础总结&#xff1a;gradle-wrapper项目根目录下的 build.gradlesetting.gradle模块中的 build.gradlelocal.properties 和 gradle.properties 组件化&#xff1a;项目下新建一个Gradle文件定义一个ext扩展区域config.gradle全局基础配置&#xff08;使用在项目…...

vulnhub靶场【哈利波特】三部曲之Aragog

前言 使用virtual box虚拟机 靶机&#xff1a;Aragog : 192.168.1.101 攻击&#xff1a;kali : 192.168.1.16 主机发现 使用arp-scan -l扫描&#xff0c;在同一虚拟网卡下 信息收集 使用nmap扫描 发现22端口SSH服务&#xff0c;openssh 80端口HTTP服务&#xff0c;Apach…...

HarmonyOS开发中,如何高效定位并分析内存泄露相关问题

HarmonyOS开发中&#xff0c;如何高效定位并分析内存泄露相关问题 (1)Allocation的应用调试方式Memory泳道Native Allocation泳道 (2)Snapshot(3)ASan的应用使用约束配置参数使能ASan方式一方式二 启用ASanASan检测异常码 (4)HWASan的应用功能介绍约束条件使能HWASan方式一方式…...

java调用ai模型:使用国产通义千问完成基于知识库的问答

整体介绍&#xff1a; 基于RAG&#xff08;Retrieval-Augmented Generation&#xff09;技术&#xff0c;可以实现一个高效的Java智能问答客服机器人。核心思路是将预先准备的问答QA文档&#xff08;例如Word格式文件&#xff09;导入系统&#xff0c;通过数据清洗、向量化处理…...

2023年第十四届蓝桥杯Scratch国赛真题—推箱子

推箱子 程序演示及其源码解析&#xff0c;可前往&#xff1a; https://www.hixinao.com/scratch/creation/show-188.html 若需在线编程&#xff0c;在线测评模考&#xff0c;助力赛事可自行前往题库中心&#xff0c;按需查找&#xff1a; https://www.hixinao.com/ 题库涵盖…...

银河麒麟V10-SP1设置redis开机自启

前言&#xff1a; redis安装请看&#xff1a;银河麒麟V10-SP1离线安装redis5.0.1_银河麒麟v10 redis5.0-CSDN博客 一、编辑自启文件 vim /etc/systemd/system/redis.service [Unit] DescriptionRedis In-Memory Data Store Afternetwork.target [Service] Typeforking ExecS…...

释放超凡性能,打造鸿蒙原生游戏卓越体验

11月26日在华为Mate品牌盛典上&#xff0c;全新Mate70系列及多款全场景新品正式亮相。在游戏领域&#xff0c;HarmonyOS NEXT加持下游戏的性能得到充分释放。HarmonyOS SDK为开发者提供了软硬协同的系统级图形加速解决方案——Graphics Accelerate Kit&#xff08;图形加速服务…...

Node.js 实战: 爬取百度新闻并序列化 - 完整教程

很多时候我们需要爬取一些公开的网页内容来做一些数据分析和统计。而多数时候&#xff0c;大家会用到python &#xff0c;因为实现起来很方便。但是其实Node.js 用来爬取网络内容&#xff0c;也是非常强大的。 今天我向大家介绍一下我自己写的一个百度新闻的爬虫&#xff0c;可…...

106.【C语言】数据结构之二叉树的三种递归遍历方式

目录 1.知识回顾 2.分析二叉树的三种遍历方式 1.总览 2.前序遍历 3.中序遍历 4.后序遍历 5.层序遍历 3.代码实现 1.准备工作 2.前序遍历函数PreOrder 测试结果 3.中序遍历函数InOrder 测试结果 4.后序遍历函数PostOrder 测试结果 4.底层分析 1.知识回顾 在99.…...

qt QToolButton详解

1、概述 QToolButton是Qt框架中的一个控件&#xff0c;它继承自QAbstractButton。QToolButton通常用于工具栏&#xff08;QToolBar&#xff09;中&#xff0c;提供了一种快速访问命令或选项的方式。与普通的QPushButton按钮相比&#xff0c;QToolButton通常只显示一个图标而不…...

2024年大热,Access平替升级方案,也适合Excel用户

欢迎各位看官&#xff0c;您来了&#xff0c;就对了&#xff01; 您多半是Access忠实粉丝&#xff0c;至少是excel用户&#xff0c;亦或是WPS用户吧。那就对了&#xff0c;今天的分享肯定对您有用。 本文1100字&#xff0c;阅读时长2分50秒&#xff01; 现实总是不尽人意&am…...

探索Scala的模式匹配:身份证识别与等级判定!!! #Scala # scala #匹配模式

在Scala编程语言中&#xff0c;模式匹配是一个强大且表达力丰富的特性&#xff0c;它允许我们以声明式的方式处理多种情况。今天&#xff0c;我们将通过两个有趣的例子来展示Scala模式匹配的魅力&#xff1a;身份证号识别和等级判定。 1. 身份证号识别&#xff1a;定位你的家乡…...

python数据分析之爬虫基础:爬虫介绍以及urllib详解

前言 在数据分析中&#xff0c;爬虫有着很大作用&#xff0c;可以自动爬取网页中提取的大量的数据&#xff0c;比如从电商网站手机商品信息&#xff0c;为市场分析提供数据基础。也可以补充数据集、检测动态变化等一系列作用。可以说在数据分析中有着相当大的作用&#xff01;…...

【星海随笔】syslinux

Ubuntu相关资料 https://www.pugetsystems.com/labs/hpc/ubuntu-22-04-server-autoinstall-iso/#Step_2_Unpack_files_and_partition_images_from_the_Ubuntu_2204_live_server_ISO https://launchpad.net/ubuntu/source/squashfs-tools/1:4.6.1-1build1 sudo tar -xf my_compu…...

力扣C语言刷题记录 (二)移除元素

给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#xff0c;您需要执行以下操作&#xff1a; 更改…...

【Vue3】【Naive UI】<NAutoComplete>标签

【Vue3】【Naive UI】标签 <NAutoComplete> 是 Naive UI 库中的一个组件&#xff0c;用于实现自动完成或联想输入功能。 它允许用户在输入时看到与当前输入匹配的建议列表&#xff0c;从而帮助用户更快地填写表单字段。 这个组件通常用于搜索框、地址输入等场景&#xff…...

【Halcon】使用均值滤波出现假边怎么办?

在图像处理过程中,均值滤波是一种常见的平滑技术,用于减少图像中的噪声。然而,当应用于具有显著边缘或对比度变化的图像时,均值滤波可能会导致“假边”现象,即原本不存在的边缘在滤波后变得明显。以下是如何在Halcon中处理这一问题,并提供一个完整的示例代码。 示例背景…...

Flask+Minio实现断点续传技术教程

什么是MinIO MinIO是一个高性能的分布式对象存储服务&#xff0c;与Amazon S3 API兼容。它允许用户存储和检索任意规模的数据&#xff0c;非常适合于使用S3 API的应用程序。MinIO支持多租户存储&#xff0c;提供高可用性、高扩展性、强一致性和数据持久性。它还可以作为软件定义…...

JAVA设计模式,动态代理模式

动态代理&#xff08;Dynamic Proxy&#xff09;是Java中一种非常有用的设计模式。它允许在运行时创建一个实现了一组给定接口的新类。这种模式主要用于当需要为某个对象提供一个代理以控制对该对象的访问时。通过这种方式&#xff0c;可以添加额外的功能&#xff0c;如事务管理…...

HTML 快速上手

目录 一. HTML概念 二. HTML标签 1. 标题标签 2. 段落标签 3. 换行标签 4. 图片标签 5. 超链接标签 6. 表格标签 7. 表单标签 7.1 form 标签 7.2 input 标签 (1) 文本框 (2) 单选框 (3) 密码框 (4) 复选框 (5) 普通按钮 (6) 提交按钮 8. select标签 9. 无语义…...

【计算机视觉算法与应用】模板匹配、图像配准

目录 1. 基于灰度值的模板匹配 2. 基于相关性的模板匹配 3. 基于形状的模板匹配 4. 基于组件的模板识别 5. 基于形变的模板匹配 6. 基于描述符的模板匹配 7. 基于点的模板匹配 性能比较 模板匹配的算法实现需要结合具体需求和应用场景来选择方法。以下是基于 OpenCV 的…...

【Linux】设计文件系统(C实现)

要求&#xff1a; (1)可以实现下列几条命令 dir 列文件目录 create 创建文件 delete 删除文件 read 读文件 write 写文件 (2)列目录时要列出文件名、存取权限&#xff08;八进制&#xff09;、文件长度、时间&#xff08;创建时间&#xff0c;修改时间以及…...

详解Rust多线程编程

文章目录 多线程模型创建和管理线程自定义线程行为线程传递数据线程间通信线程池错误处理与线程Condvar(条件变量)无锁并发高性能并发库 Rust的多线程编程提供了一种安全、高效的方式来进行并发操作。Rust的并发性设计原则之一是确保线程安全&#xff0c;同时避免运行时的开销&…...

el-upload上传多个文件,一次请求,Django接收

1、:file-list"fileList" :on-change"handleChange" 将文件赋值到fileList 2、 :auto-upload"false" 手动触发上传 写个按钮点击执行这个 this.$refs.upload.submit(); 3、自己写上传&#xff0c;不会再触发上传成功或失败回调 4、 request.FI…...

Python实现网站资源批量下载【可转成exe程序运行】

Python实现网站资源批量下载【可转成exe程序运行】 背景介绍解决方案转为exe可执行程序简单点说详细了解下 声明 背景介绍 发现 宣讲家网 的PPT很好&#xff0c;作为学习资料使用很有价值&#xff0c;所以想下载网站的PPT课件到本地&#xff0c;但是由于网站限制&#xff0c;一…...

《JavaScript高级程序设计》读书笔记 20

感谢点赞、关注和收藏&#xff01; 原始值包装类型 为了方便操作原始值&#xff0c;ECMAScript 提供了 3 种特殊的引用类型&#xff1a;Boolean、Number 和 String。每当用到某个原始值的方法或属性时&#xff0c;后台都会创建一个相应原始包装类型的对象&#xff0c;从而暴露…...

ASP.NET Core项目中使用SqlSugar连接多个数据库的方式

之前学习ASP.NETCore及SqlSugar时都是只连接单个数据库处理数据&#xff0c;仅需在Program文件中添加ISqlSugarClient的单例即可&#xff08;如下代码所示&#xff09;。 builder.Services.AddSingleton<ISqlSugarClient>(s > {SqlSugarScope sqlSugar new SqlSugar…...