排序算法:归并排序,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) 来存储临时数组。这在内存受限的情况下可能是一个问题。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10、billu-b0x2

难度 中 目标 root权限 首先确定靶机ip地址 netdiscover -i eth0 -r 192.168.189.0/24 kali 192.168.189.58 靶机 192.168.189.184 信息收集端口扫描 看到一个80和8080&#xff0c;先重点摸一下网站的内容 然后看到信息里有个robots.txt 首先就去访问一下 看到有许多不允许…

【C语言】数组和函数实践:扫雷游戏

扫雷游戏 1. 扫雷游戏分析和设计1.1 扫雷游戏的功能说明1.2 游戏的分析和设计1.2.1 数据结构的分析1.2.2 ⽂件结构设计 2. 扫雷游戏的代码实现&#xff08;1&#xff09;菜单menu函数&#xff08;2&#xff09;设计main函数&#xff08;3&#xff09;设计game函数&#xff08;4…

华为od机试真题:求幸存数之和(Python)

2024华为OD机试&#xff08;C卷D卷&#xff09;最新题库【超值优惠】Java/Python/C合集 题目描述 给一个正整数列nums&#xff0c;一个跳数jump&#xff0c;及幸存数量left。运算过程为:从索引为0的位置开始向后跳&#xff0c;中间跳过 J 个数字&#xff0c;命中索引为 J1的数…

腾讯云短信服务的开通流程

目录 一、开通服务二、创建secretId和secretKey三、创建应用四、创建实名资质五、创建签名六、创建正文模板一、开通服务 从控制台进入短信模块,点击【开始接入】开通服务: 认证主体首次开通短信服务可获赠国内短信,免费试用: 二、创建secretId和secretKey 创建链接:…

创意无限:11个设计圈热议的UI设计灵感网站集锦

无论你是一个经验丰富的UI设计师还是一个新的UI设计师&#xff0c;拥有一些高质量、可靠的UI设计网站灵感库都能加速你的设计过程。借助灵感资源&#xff0c;您可以更快、更有效地启动该项目。与此同时&#xff0c;优秀的UI设计网站也能帮助您探索新的设计解决方案&#xff0c;…

个性化你的生产力工具:待办事项App定制指南

国内外主流的10款待办事项软件对比&#xff1a;PingCode、Worktile、滴答清单、番茄ToDo、Teambition、Todoist、Microsoft To Do、TickTick、Any.do、Trello。 在寻找合适的待办事项软件时&#xff0c;你是否感到选择众多、难以决断&#xff1f;一个好的待办事项工具可以大大提…

【C++BFS】802. 找到最终的安全状态

本文涉及知识点 CBFS算法 LeetCode802. 找到最终的安全状态 有一个有 n 个节点的有向图&#xff0c;节点按 0 到 n - 1 编号。图由一个 索引从 0 开始 的 2D 整数数组 graph表示&#xff0c; graph[i]是与节点 i 相邻的节点的整数数组&#xff0c;这意味着从节点 i 到 graph…

专硕复试线298/295!哈尔滨理工大学计算机考研考情分析!

哈尔滨理工大学&#xff08;Harbin University of Science and Technology&#xff09;&#xff0c;位于哈尔滨市&#xff0c;是黑龙江省人民政府与国家国防科技工业局共建高校&#xff0c;入选“中西部基础能力建设工程”高校、国家“特色重点学科项目”建设高校、教育部“卓越…

MCU单片机GPIO初始化该按什么顺序配置?为什么初始化时有电平跳变?

GPIO初始化时有时钟配置、模式配置、输出配置、复用配置&#xff0c;那么在编写初始化代码时&#xff0c;到底该按什么顺序执行呢&#xff1f;如果顺序不当那初始化过程可能会出现短暂的电平跳变。 第一步&#xff0c;初始化MCU外设时&#xff0c;一般都需要先打开对应寄存器的…

【Qwen-Audio部署实战】Qwen-Audio-Chat模型之对话机器人部署测试

系列篇章&#x1f4a5; No.文章1【Qwen部署实战】探索Qwen-7B-Chat&#xff1a;阿里云大型语言模型的对话实践2【Qwen2部署实战】Qwen2初体验&#xff1a;用Transformers打造智能聊天机器人3【Qwen2部署实战】探索Qwen2-7B&#xff1a;通过FastApi框架实现API的部署与调用4【Q…

【Hot100】LeetCode—169. 多数元素

目录 题目1- 思路2- 实现⭐169. 多数元素——题解思路 3- ACM 实现 题目 原题连接&#xff1a;169. 多数元素 1- 思路 定义两个变量 一个是 count&#xff1a;维护当前元素的出现次数一个是 ret &#xff1a;维护当前元素 思路 遍历整个数组**①如果 count 0 **&#xff…

【TS】TypeScript中的接口(Interface):对象类型的强大工具

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 TypeScript中的接口(Interface):对象类型的强大工具引言1. 接口的基本概念1.1 什…

APP抓包之 Burpsuite+MuMu模拟器12抓包

写在前面 高版本的安卓不能直接安装证书了&#xff0c;比较麻烦。步骤如下。 前置工作 安装adb https://blog.csdn.net/x2584179909/article/details/108319973 安装openssl https://blog.csdn.net/zyhse/article/details/108186278 adb配置环境变量&#xff0c;openssl下载…

如何用Python删除电脑中的重复文件?

在生活中&#xff0c;我们经常会遇到电脑中文件重复的情况。 在文件较少的情况下&#xff0c;这类情况还比较容易处理&#xff0c;最不济就是一个个手动对比删除&#xff1b; 而在重复文件很多的时候&#xff0c;我们很难保证把重复文件全部删完。 这里给大家带来了一个便捷…

【C++的剃刀】我不允许你还不会AVL树

​ 学习编程就得循环渐进&#xff0c;扎实基础&#xff0c;勿在浮沙筑高台 循环渐进Forward-CSDN博客 Hello,这里是kiki&#xff0c;今天继续更新C部分&#xff0c;我们继续来扩充我们的知识面&#xff0c;我希望能努力把抽象繁多的知识讲的生动又通俗易懂&#xff0c;今天要…

JavaScript递归菜单栏

HTML就一个div大框架 <div class"treemenu"></div> 重中之重的JavaScript部分他来啦&#xff01; 注释也很清楚哟家人们&#xff01; let data; let arr []; let cons;let xhr new XMLHttpRequest(); // 设置请求方式和请求地址 xhr.open(get, ./js…

leetcode958. 二叉树的完全性检验,层序遍历的巧用

leetcode958. 二叉树的完全性检验 给你一棵二叉树的根节点 root &#xff0c;请你判断这棵树是否是一棵 完全二叉树 。 在一棵 完全二叉树 中&#xff0c;除了最后一层外&#xff0c;所有层都被完全填满&#xff0c;并且最后一层中的所有节点都尽可能靠左。最后一层&#xff0…

NAS 软件大盘点:瞧瞧哪个被你遗漏了

很多人都听说过NAS&#xff0c;也有很多人正在使用NAS&#xff0c;而NAS用户通常需要安装一些软件来扩展其功能&#xff0c;毕竟NAS的功能实在是太多了&#xff0c;光是部署与调试就要耗费大量的时间&#xff0c; 小宝集合了NAS相关实用工具&#xff0c;无论是群晖、威联通还是…

华硕电脑怎么录屏?3个高效实用的方法

华硕电脑作为一款备受青睐的电脑品牌&#xff0c;拥有丰富的功能和工具&#xff0c;其中包括强大的录屏功能。然而&#xff0c;对于许多华硕电脑用户来说&#xff0c;如何利用这一功能可能会感到困惑。 本文将带您探索华硕电脑的录屏功能&#xff0c;为您揭示华硕电脑怎么录屏…

Web安全学习顺序:从零到精通的指南

随着互联网的迅猛发展&#xff0c;Web安全已成为一个日益重要的领域。无论是企业还是个人&#xff0c;都需要关注并提升自身的Web安全防护能力。对于初学者而言&#xff0c;如何系统地学习Web安全知识&#xff0c;掌握相关技能&#xff0c;成为了一个亟待解决的问题。本文将为你…