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

排序算法:归并排序,golang实现

目录

前言

归并排序

代码示例

1. 算法包

2. 归并排序代码

3. 模拟程序

4. 运行程序

5. 从大到小排序

归并排序主要操作

1. 合并

2. 分割(Divide)与递归排序(Conquer)

总体思想

循环次数测试

假如 10 条数据进行排序

假如 20 条数据进行排序

假如 30 条数据进行排序

假设 5000 条数据,对比 冒泡、选择、插入、快速、堆

归并排序的适用场景

1. 大数据集

2. 链表排序

3. 外部排序

4. 稳定性需求


前言

在实际场景中,选择合适的排序算法对于提高程序的效率和性能至关重要,本节课主要讲解"归并排序"的适用场景及代码实现。

归并排序

归并排序(Merge Sort)是一种分而治之的排序算法。它将一个大列表分成两个小列表,分别对这两个小列表进行排序,然后将排序好的小列表合并成一个最终的排序列表。归并排序的关键在于合并(Merge)过程,它确保了在合并的过程中,两个已排序的序列被合并成一个新的、有序的序列。

代码示例

下面我们使用Go语言实现一个归并排序

1. 算法包

创建一个 pkg/algorithm.go

touch pkg/algorithm.go

如果看过上节课的堆排序,则已存在该文件,我们就不需要再创建了

2. 归并排序代码

打开 pkg/algorithm.go 文件,代码如下

从小到大 排序

package pkg// BubbleSort 冒泡排序
...// SelectionSort 选择排序
...// InsertionSort 插入排序
...// QuickSort 快速排序
...// partition 分区操作
...// HeapSort 堆排序
...// heapify 将以 i 为根的子树调整为最大堆
...// MergeSort 归并排序
func MergeSort(arr []int) []int {if len(arr) <= 1 {return arr}// 找到中点,分割数组mid := len(arr) / 2left := MergeSort(arr[:mid])right := MergeSort(arr[mid:])// 合并两个已排序的切片return merge(left, right)
}// merge 函数用于合并两个已排序的切片
func merge(left, right []int) []int {var result []inti, j := 0, 0for i < len(left) && j < len(right) {if left[i] < right[j] {result = append(result, left[i])i++} else {result = append(result, right[j])j++}}// 如果左侧有剩余,则追加到结果切片result = append(result, left[i:]...)// 如果右侧有剩余,则追加到结果切片result = append(result, right[j:]...)return result
}

3. 模拟程序

打开 main.go 文件,代码如下:

package mainimport ("demo/pkg""fmt"
)func main() {// 定义一个切片,这里我们模拟 10 个元素arr := []int{98081, 27887, 31847, 84059, 2081, 41318, 54425, 22540, 40456, 3300}fmt.Println("arr 的长度:", len(arr))fmt.Println("Original data:", arr) // 先打印原始数据newArr := pkg.MergeSort(arr)       // 调用归并排序fmt.Println("New data:  ", newArr) // 后打印排序后的数据
}

4. 运行程序

go run main.go

能发现, Original data 后打印的数据,正是我们代码中定义的切片数据,顺序也是一致的。

New Data 后打印的数据,则是经过归并排序后的数据,是从小到大的。

5. 从大到小排序

如果需要 从大到小 排序也是可以的,在代码里,需要将两个 if 判断比较的 符号 进行修改。

修改 pkg/algorithm.go 文件:

package pkg// BubbleSort 冒泡排序
...// SelectionSort 选择排序
...// InsertionSort 插入排序
...// QuickSort 快速排序
...// partition 分区操作
...// HeapSort 堆排序
...// heapify 将以 i 为根的子树调整为最大堆
...// MergeSort 归并排序
func MergeSort(arr []int) []int {if len(arr) <= 1 {return arr}// 找到中点,分割数组mid := len(arr) / 2left := MergeSort(arr[:mid])right := MergeSort(arr[mid:])// 合并两个已排序的切片return merge(left, right)
}// merge 函数用于合并两个已排序的切片
func merge(left, right []int) []int {var result []inti, j := 0, 0for i < len(left) && j < len(right) {if left[i] > right[j] {result = append(result, left[i])i++} else {result = append(result, right[j])j++}}// 如果左侧有剩余,则追加到结果切片result = append(result, left[i:]...)// 如果右侧有剩余,则追加到结果切片result = append(result, right[j:]...)return result
}

只需要一丁点的代码即可

从 package pkg 算第一行,上面示例中在第四十五行代码,我们将 "<" 改成了 ">" ,这样就变成了 从大到小排序了

归并排序主要操作

主要操作包括 分割合并


1. 合并

合并操作由 merge 函数实现,它接收两个已排序的切片 left 和 right,并返回一个新的、包含两个切片所有元素且已排序的切片。

  • 初始化:首先,创建一个空的切片 result 用于存储合并后的结果。同时,使用两个索引 i 和 j 分别指向 left 和 right 的起始位置
  • 比较与合并:然后,使用一个循环,比较 left[i] 和 right[j] 的大小。将较小的元素追加到 result 中,并移动相应的索引。这个过程一直持续到任一切片中的所有元素都被添加到 result 中
  • 追加剩余元素:如果 left 和 right 中还有剩余的元素(即某个切片的索引没有遍历完),则直接将剩余的元素追加到 result 的末尾。这是因为在循环结束时,剩余的元素一定是已排序的(它们来自原始的已排序切片)

2. 分割(Divide)与递归排序(Conquer)

分割与递归排序操作由 mergeSort 函数实现。

  • 基本情况:如果输入的切片 arr 的长度小于或等于 1,则不需要排序,直接返回该切片。因为单个元素或空切片都可以被认为是已排序的
  • 分割:找到切片的中点 mid,将切片分为两部分:arr[:mid] 和 arr[mid:]
  • 递归排序:对着两部分分别调用 mergeSort 函数进行递归排序。这会将问题分解成更小的子问题,直到子问题小到满足基本情况
  • 合并:最后,使用 merge 函数将这两个递归排序后的切片合并成一个有序的切片,并返回该切片

总体思想

归并排序通过递归地将数组分解成越来越小的半子表,对半子表排序,然后再将排好序的半子表合并成有序的表来工作。这个过程需要额外的存储空间来存放合并后的数组,因此其空间复杂度为 O(n)。然而,归并排序的时间复杂度是稳定的 O(n log n),并且由于其分治特性,它在实际应用中非常有效,尤其是在处理大数据集时。

循环次数测试

参照上面示例进行测试(因考虑到每次手动输入 10 条、20 条、30 条数据太繁琐,所以我写了一个函数,帮助我自动生成 0到100000 的随机整数)

假如 10 条数据进行排序

总计循环了 32 

假如 20 条数据进行排序

总计循环了 84 

假如 30 条数据进行排序

总计循环了 137 

假设 5000 条数据,对比 冒泡、选择、插入、快速、堆

  • 冒泡排序:循环次数 12,502,499 次
  • 选择排序:循环次数 12,502,499 次
  • 插入排序:循环次数 6,323,958 次
  • 快速排序:循环次数 74,236 次
  • 堆排序:循环次数 59,589 次
  • 归并排序:循环次数 60,288 次

归并排序的适用场景

归并排序在以下场景表现良好

1. 大数据集

对于非常大的数据集,归并排序通常比快速排序或插入排序更有效,因为归并排序的时间复杂度是 O(n log n),并且它的性能相对稳定,不会因数据集的不同而大幅度变化

2. 链表排序

由于归并排序在合并过程中不需要额外的空间(除了递归栈),所以在链表排序时非常高效。链表数据结构的特性使得分割和合并操作相对简单

3. 外部排序

当数据集太大,无法全部加载到内存时,可以使用归并排序的外部版本。在这个版本中,数据被分割成多个块,每块单独排序后存储在磁盘上,然后通过归并操作将它们合并成一个有序的文件

4. 稳定性需求

归并排序是稳定的排序算法,这意味着相等的元素在排序后仍然保持原来的顺序。这在需要保持元素原始顺序的某些应用中非常有用

尽管归并排序在很多场景下都很有用,但它也有缺点,主要是需要额外的空间 O(n) 来存储临时数组。这在内存受限的情况下可能是一个问题。

相关文章:

排序算法:归并排序,golang实现

目录 前言 归并排序 代码示例 1. 算法包 2. 归并排序代码 3. 模拟程序 4. 运行程序 5. 从大到小排序 归并排序主要操作 1. 合并 2. 分割&#xff08;Divide&#xff09;与递归排序&#xff08;Conquer&#xff09; 总体思想 循环次数测试 假如 10 条数据进行排序…...

CSS 的工作原理

我们已经学习了CSS的基础知识,它的用途以及如何编写简单的样式表。在本课中,我们将了解浏览器如何获取 CSS 和 HTML 并将其转换为网页。 先决条件:已安装基本软件,了解处理文件的基本知识以及 HTML 基础知识(学习 HTML 简介。目的:要了解浏览器如何解析 CSS 和 HTML 的基…...

买完就后悔?只需几步教你 Apple 怎么申请退款

苹果系统不同于 Android 系统的一点在于下载某一些 App 的时候需要付费才能下载&#xff0c;但是有时候在我们付费之后突然就不想要购买了怎么办呢&#xff1f;别急这可以申请退款&#xff0c;你知道 Apple 怎么申请退款吗&#xff1f;下面就带大家了解一下 Apple 申请退款的步…...

【保卫战】休闲小游戏 链游

...

如何构建自己的交易机器人开发环境

作者&#xff1a;老余捞鱼 原创不易&#xff0c;转载请标明出处及原作者。 写在前面的话&#xff1a; 本文主要讲解如何构建一个交易机器人开发环境。描述具体的步骤和工具&#xff0c;包括使用 GitHub Codespaces、Visual Studio Code&#xff08;VS Code&#xff09;…...

解决WordPress文章引用的图片不显示问题

在使用WordPress发布文章时&#xff0c;有时会遇到复制发布的文档中包含的外链图片无法正常显示的问题。然而&#xff0c;当我们将图片路径复制到浏览器中单独打开时&#xff0c;图片却可以正常显示。以下是解决这一问题的方法。 问题描述 当你在WordPress文章中引用外链图片…...

商业银行国际结算规模创新高,合合信息AI助力金融行业智能处理多版式文档

随着我国外贸新业态的快速增长&#xff0c;银行国际结算业务在服务实体经济发展、促进贸易投资便利化进程中发挥了越来越重要的作用。根据中国银行业协会近日发布的《中国贸易金融行业发展报告&#xff08;2023—2024&#xff09;》&#xff0c;2023年我国主要商业银行国际结算…...

数字芯片设计验证经验分享:将ASIC IP核移植到FPGA上——更新概念并推动改变以完成充满挑战的任务!

作者&#xff1a;Philipp Jacobsohn&#xff0c;SmartDV首席应用工程师 Sunil Kumar&#xff0c;SmartDV FPGA设计总监 本系列文章从数字芯片设计项目技术总监的角度出发&#xff0c;介绍了如何将芯片的产品定义与设计和验证规划进行结合&#xff0c;详细讲述了在FPGA上使用I…...

【Linux】Linux下的日志(日常级)

日志是日后工作中非常重要的一部分&#xff0c;现在写一份简单的日志项目可以帮助我们熟悉并理解原理。 目录 设计思路&#xff1a;一些实现细节&#xff1a;代码&#xff1a;日志的使用方法&#xff1a; 设计思路&#xff1a; 图示是我们的最终目的。 设计一个类&#xff0…...

手把手教你如何在Linux上轻松安装Python,告别编程入门难题

导语&#xff1a; Python作为当下最热门的编程语言之一&#xff0c;受到了越来越多人的喜爱。对于Linux用户来说&#xff0c;掌握如何在Linux上安装Python至关重要。今天&#xff0c;就让我带领大家一步步在Linux上安装Python&#xff0c;让你轻松迈入编程世界&#xff01; 一…...

XSS-labs靶场(超详解)1-20关——附原码

level1 原码 <!DOCTYPE html><!--STATUS OK--><html> <head> <meta http-equiv"content-type" content"text/html;charsetutf-8"> <script> window.alert function() { confirm("完成的不错&#xff0…...

【网络安全】LockBit病毒入侵揭秘:如何防范与应对

文章目录 前言 主要特征攻击手段演进历程主要威胁防范与对策 如何入门学习网络安全【黑客】 【----帮助网安学习&#xff0c;以下所有学习资料文末免费领取&#xff01;----】 大纲学习教程面试刷题 资料领取 前言 在数字时代&#xff0c;随着科技的飞速发展&#xff0c;网络…...

《开源大模型食用指南》适合中国宝宝的部署教程,基于Linux环境快速部署开源大模型

本项目是一个围绕开源大模型、针对国内初学者、基于 AutoDL 平台的中国宝宝专属大模型教程&#xff0c;针对各类开源大模型提供包括环境配置、本地部署、高效微调等技能在内的全流程指导&#xff0c;简化开源大模型的部署、使用和应用流程&#xff0c;让更多的普通学生、研究者…...

体验教程:通义灵码陪你备战求职季

本场景将带大家体验在技术面试准备场景下&#xff0c;如何通过使用阿里云通义灵码实现高效的编程算法题练习 、代码优化、技术知识查询等工作&#xff0c;帮助开发者提升实战能力&#xff0c;更加从容地应对面试挑战。主要包括&#xff1a; 1、模拟题练习&#xff1a;精心挑选…...

(070)爬楼梯

思路&#xff1a;一次爬一个或者一次爬两个楼梯,终止条件&#xff0c;即是当n1或n2时&#xff0c;完成操作&#xff0c;当n>2时&#xff0c;总方法就等于一次爬一个楼梯的方法数加上一次爬两个楼梯的方法数。 解法一&#xff1a;递归解法 if(n 1)return 1;if(n 2)return 2…...

el-table 表格序号列前端实现递增,切换分页不从头开始

<el-table-column type"index" width"55" label"序号" :index"hIndex"> </el-table-column> 分页 <el-pagination size-change"handleSizeChange" current-change"handleCurrentChange"> <…...

NSSCTF-Web题目27(Nginx漏洞、php伪协议、php解析绕过)

目录 [HNCTF 2022 WEEK2]easy_include 1、题目 2、知识点 3、思路 [NSSRound#8 Basic]MyDoor 4、题目 5、知识点 6、思路 [HNCTF 2022 WEEK2]easy_include 1、题目 2、知识点 nginx日志漏洞执行系统命令 3、思路 打开题目&#xff0c;出现源码 题目要我们上传一个fi…...

分割损失:Dice vs. IoU

NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 对于医学影像分割&#xf…...

SpringBoot整合Juint,ssm框架

目录 SpringBoot整合Juint 1.导入相关的依赖 2.创建测试类&#xff0c;使用注解SpringBootTest SpringBoot整合ssm框架 1.使用脚手架创建Spring项目 2.修改pom.xml 我先修改了SpringBoot的版本&#xff0c;修改为2.3.10.RELEASE&#xff0c;因为SpringBoot版本太高会出现…...

基于supervisor制作基于环境变量配置的redis

背景&#xff1a; redis 的镜像很多很多&#xff0c;但都需要直接修改配置文件&#xff0c;不符合我们公司当前环境变量解决一切容易配置的思路。 材料&#xff1a; 1、CentOS-Base.repo [base] nameCentOS-$releasever enabled1 failovermethodpriority baseurlhttp://mirr…...

动态规划part01 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯

509. 斐波那契数 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xff0c;其中 …...

CSS实现图片边框酷炫效果

一、前言 我们在浏览一些网页时&#xff0c;经常会看到一些好看酷炫的元素边框效果&#xff08;如下图&#xff09;&#xff0c;那么这些效果是怎么实现的呢&#xff1f;我们知道&#xff0c;一般的边框&#xff0c;要么是实线&#xff0c;要么是虚线&#xff08;点状&#xf…...

遇到 MySQL 死锁问题如何解决?

终于来到死锁检查线程的第三步&#xff0c;可以解决死锁了。 作者&#xff1a;操盛春&#xff0c;爱可生技术专家&#xff0c;公众号『一树一溪』作者&#xff0c;专注于研究 MySQL 和 OceanBase 源码。 爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0…...

Pyinstaller打包OSError: could not get source code【终极解决】

pyinstaller 打包的时候&#xff0c;发现只要是torch.jit.script装饰的函数&#xff0c;会报以下错误&#xff1a; Traceback (most recent call last):File "torch/_sources.py", line 25, in get_source_lines_and_fileFile "inspect.py", line 1123, i…...

【计算机毕业设计】707高校宿舍管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…...

从C++看C#托管内存与非托管内存

进程的内存 一个exe文件&#xff0c;在没有运行时&#xff0c;其磁盘存储空间格式为函数代码段全局变量段。加载为内存后&#xff0c;其进程内存模式增加为函数代码段全局变量段函数调用栈堆区。我们重点讨论堆区。 托管堆与非托管堆 C# int a10这种代码申请的内存空间位于函…...

Linux进程间通信--IPC之无名管道

进程间通信&#xff08;IPC&#xff0c;InterProcess Communication&#xff09;是指在不同进程之间传播或交换信息。 IPC的方式通常有管道&#xff08;包括无名管道和命名管道&#xff09;、消息队列、信号量、共享存储、Socket、Streams支持不同主机上的两个进程的IPC。...

Oracle19c数据库system密码锁定

一、在oracle 19c数据库中&#xff0c;cdb中system用户被锁定&#xff0c;locked 二、所在的pdb中的system用户状态是正常的&#xff0c;但不可用&#xff0c;连接的时候提示账号已锁定 三、解决 在cdb中将system用户解锁。 alter user system account unlock;...

java之hashCode() 方法和 equals(Object obj) 方法之间的关系

1、 hashCode() 方法和 equals(Object obj) 在Java中&#xff0c;hashCode() 方法和 equals(Object obj) 方法之间的关系是紧密相连的&#xff0c;特别是在使用基于哈希的集合&#xff08;如 HashSet、HashMap、HashTable 等&#xff09;时。这两个方法共同决定了对象在哈希表…...

首届「中国可观测日」圆满落幕

首届中国可观测日&#xff08;Observability Day&#xff09;在上海圆满落幕&#xff0c;为监控观测领域带来了一场技术盛宴。作为技术交流的重要平台&#xff0c;此次活动不仅促进了观测云与亚马逊云科技之间的深化合作&#xff0c;更标志着双方共同推动行业发展的重要里程碑。…...

网站建设公司如何拓宽业务/seo关键词排名公司

作者&#xff1a;UncleChen来源&#xff1a;http://unclechen.github.io/最近在工作中遇到写一些API&#xff0c;这些API的请求参数非常多&#xff0c;嵌套也非常复杂&#xff0c;如果参数的校验代码全部都手动去实现&#xff0c;写起来真的非常痛苦。正好Spring轮子里面有一个…...

勉费申请做网站/关键词搜索神器

关于Spring中基于xml文件配置bean的详细总结&#xff08;spring 4.1.0&#xff09; 一、Spring中的依赖注入方式介绍 依赖注入有三种方式 属性注入构造方法注入工厂方法注入&#xff08;很少使用&#xff0c;不推荐&#xff0c;本文不再介绍&#xff09;属性注入 通过 setter…...

网站的建设与管理/武汉做seo

Linux 启动过程 实模式时内存分配 从实模式切换到保护模式 启用分段&#xff0c;就是在内存里面建立段描述符表&#xff0c;将寄存器里面的段寄存器变成段选择子&#xff0c;指向某个段描述符&#xff0c;这样就能实现不同进程的切换了。启动分页。能够管理的内存变大了&#…...

2023年免费进入b站/精准客户数据采集软件

学习web编程的方法&#xff1a;1、学习html和css&#xff1b;2、学习javascript&#xff1b;3、了解web服务器&#xff1b;4、学习一门服务器端脚本语言&#xff1b;5、学习数据库及SQL语法&#xff1b;6、学习web框架。如何学习web开发&#xff0c;需要掌握哪些方面&#xff1…...

莱州网站建设公司/电商网站对比

问题提出&#xff1a;M&#xff08;如10亿&#xff09;个int整数&#xff0c;只有其中N个数重复出现过&#xff0c;读取到内存中并将重复的整数删除。 问题分析&#xff1a;我们肯定会先想到在计算机内存中开辟M个int整型数据数组&#xff0c;来one bye one读取M个int类型数组&…...

个人网站制作成品/昆明网站seo公司

1 前言本文以两道经典建模题为例, 进一步介绍 Gurobi 与 Python 的交互, 以及其在建模中的应用. 阅读本文前, 建议读者先配置好 Gurobi 环境, 并且对数学建模有一定的认识 (吹水, 不考虑绝对的严谨性)。本文也可作为建模小白的“入门指南”, 全文都是按照我的思维过程进行书写,…...