Go归并排序算法的实现方法


Posted in Golang onApril 06, 2022

今天继续基础排序算法的图解和Go 代码实现,这次分享一个时间复杂度为*** 诶,时间复杂度多少先保密,文末会有分析。这次分享的排序算法是—归并排序(Merge Sort)。

归并排序的思想

与快速排序一样,归并排序采用的也是分治的策略,把原本的问题先分解成一些小问题进行求解,再把这些小问题各自的答案修整到一起得到原本问题的答案,从而达到分而治之的目的。

归并排序算法会把要排序的序列分成长度相当的两个子序列,当分无可分每个子序列中只有一个数据的时候,就对子序列进行归并。

归并指的是把两个排序好的子序列合并成一个有序序列。该操作会一直重复执行,直到所有子序列归并为一个整体为止。

归并排序的过程下面我们依然用图例过一遍归并排序对一个序列进行排序的过程。

图例出自—《我的第一本算法书》

首先,假设有下面这样一个待排序的序列:

Go归并排序算法的实现方法

待排序的一串数字

将序列以对半分割的形式分成两段 。

Go归并排序算法的实现方法

把序列二分成两段

再继续对子序列进行对半分割,分解下去 。

Go归并排序算法的实现方法

再继续往下分

直到分无可分,每个子序列中只有一个数据 。

Go归并排序算法的实现方法

分解到每个子序列只有一个数据

接下来对分割后的数据进行合并,合并时需要将数字按从小到大的顺序排列。

Go归并排序算法的实现方法

合并序列时按大小排序

把 6 和 4 合并,合并时按照数字大小排序,合并后的顺序为【4,6】,接下来把 3 和 7 合并,合并后的顺序为【3,7】。

[继续按照大小顺序合并后面的序列](/Users/klein/Library/Application Support/typora-user-images/image-20220405142734949.png)。

下面,我们看看怎么合并【4,6】和【3,7】这两个序列。合并这种含有多个数字的子序列时,要先比较首位数字,再移动较小的数字。

Go归并排序算法的实现方法

合并多元素的序列时,从首位开始比较,小的先移动

这里要比较两个子序列的首位数字是4 和 3。由于 4 > 3,所以合并序列时先移动 3。

Go归并排序算法的实现方法

4 > 3,所以合并序列时先移动 3

接下来,再按照比较两个序列首位,小的先合并,大的留下来继续比较的规则合并两个序列。

4 小于 7,所以先移动 4 到合并的序列。

Go归并排序算法的实现方法

由于4<7,所以移动4

两个子序列剩下的元素中,6 小于 7,所以先移动 6 。

Go归并排序算法的实现方法

6 < 7 所以先移动 6

最后移动剩下的 7。

Go归并排序算法的实现方法

子序列最后剩下了7,合并到序列中去

递归执行上面的操作,直到所有的数字都合并到一个整体的序列上为止。

Go归并排序算法的实现方法

小序列合并成两个大的序列

Go归并排序算法的实现方法

再继续往完整的序列上合并

最后得到一个完整的排序完成的序列 。

Go归并排序算法的实现方法

排序完成的序列

归并排序的 Go 代码实现

下面上一个用归并排序的Go代码实现,代码很简单,实现步骤就都放在了代码的注释里,就不再多说啦,先收藏文章(也要记得点赞),等有时间了自己在电脑上运行一下试试吧。

package main

import "fmt"

// 自顶向下归并排序,排序范围在 [begin,end) 的数组
func MergeSort(array []int, begin int, end int) {
    // 元素数量大于1时才进入递归
    if end - begin &gt; 1 {

        // 将数组一分为二,分为 array[begin,mid) 和 array[mid,high)
        mid := begin + (end-begin+1)/2

        // 先将左边排序好
        MergeSort(array, begin, mid)

        // 再将右边排序好
        MergeSort(array, mid, end)

        // 两个有序数组进行合并
        merge(array, begin, mid, end)
    }
}

// 归并操作
func merge(array []int, begin int, mid int, end int) {
    // 申请额外的空间来合并两个有序数组,这两个数组是 array[begin,mid),array[mid,end)
    leftSize := mid - begin         // 左边数组的长度
    rightSize := end - mid          // 右边数组的长度
    newSize := leftSize + rightSize // 辅助数组的长度
    result := make([]int, 0, newSize)

    l, r := 0, 0
    for l &lt; leftSize &amp;&amp; r &lt; rightSize {
        lValue := array[begin+l] // 左边数组的元素
        rValue := array[mid+r]   // 右边数组的元素
        // 小的元素先放进辅助数组里
        if lValue &lt; rValue {
            result = append(result, lValue)
            l++
        } else {
            result = append(result, rValue)
            r++
        }
    }

    // 将剩下的元素追加到辅助数组后面
    result = append(result, array[begin+l:mid]...)
    result = append(result, array[mid+r:end]...)

    // 将辅助数组的元素复制回原数组,这样该辅助空间就可以被释放掉
    for i := 0; i &lt; newSize; i++ {
        array[begin+i] = result[i]
    }
    return
}

归并排序的时间复杂度

老规矩,看完算法思想和实现步骤后,我们再来分析一下归并排序算法的时间复杂度。

归并排序中,分割序列所花费的时间不算在运行时间内 (可以当作序列本来就是分 割好的)。在合并两个已排好序的子序列时,只需依次比较处在序列首位数据的大小,然后移动较小的数据,因此只需花费和两个子序列的长度相应的运行时间。也就是说,完成一行归并所需的运行时间取决于这一行的数据量。

看一下这个图便能得知,无论哪一行都是 n 个数据,所以每行的运行时间都为 O(n)。

Go归并排序算法的实现方法

归并排序每一行的数据都是 n 个

而将长度为 n 的序列对半分割直到只有一个数据为止时,可以分成 行,因此,总共有 log2n 行。也就是说,总的运行时间为 ,这与前面讲到的快速排序相同。

到此这篇关于Go归并排序算法的实现方法的文章就介绍到这了,更多相关go归并排序算法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
go:垃圾回收GC触发条件详解
Apr 24 Golang
goland 恢复已更改文件的操作
Apr 28 Golang
golang gopm get -g -v 无法获取第三方库的解决方案
May 05 Golang
Golang 编译成DLL文件的操作
May 06 Golang
解决Goland 同一个package中函数互相调用的问题
May 06 Golang
使用golang编写一个并发工作队列
May 08 Golang
Golang标准库syscall详解(什么是系统调用)
May 25 Golang
Golang二维数组的使用方式
May 28 Golang
Golang生成Excel文档的方法步骤
Jun 09 Golang
Go语言怎么使用变长参数函数
Jul 15 Golang
Go语言编译原理之变量捕获
Aug 05 Golang
go goth封装第三方认证库示例详解
Aug 14 Golang
golang操作rocketmq的示例代码
Apr 06 #Golang
victoriaMetrics库布隆过滤器初始化及使用详解
如何解决goland,idea全局搜索快捷键失效问题
golang为什么要统一错误处理
简单聊聊Golang中defer预计算参数
Mar 25 #Golang
Go 中的空白标识符下划线
golang生成vcf通讯录格式文件详情
You might like
特转载一高手总结PHP学习资源和链接.
2006/12/05 PHP
php自动获取目录下的模板的代码
2010/08/08 PHP
PHP中数组合并的两种方法及区别介绍
2012/09/14 PHP
php中url函数介绍及使用示例
2014/02/13 PHP
php无序树实现方法
2015/07/28 PHP
PHP生成各种常见验证码和Ajax验证过程
2016/01/10 PHP
PHP类相关知识点实例总结
2016/09/28 PHP
js cookies 常见网页木马挂马代码 24小时只加载一次
2009/04/13 Javascript
javascript 触发事件列表 比较不错
2009/09/03 Javascript
js关闭浏览器窗口及检查浏览器关闭事件
2013/09/03 Javascript
JS延时器提示框的应用实例代码解析
2016/04/27 Javascript
jQuery.form.js插件不能解决连接超时(timeout)的原因分析及解决方法
2016/10/14 Javascript
js+html5实现复制文字按钮
2017/07/15 Javascript
五步轻松实现JavaScript HTML时钟效果
2020/03/25 Javascript
基于vue开发的在线付费课程应用过程
2018/01/25 Javascript
JS实现的缓冲运动效果示例
2018/04/30 Javascript
[54:54]Newbee vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
python实现simhash算法实例
2014/04/25 Python
Python中利用原始套接字进行网络编程的示例
2015/05/04 Python
Python设计模式编程中Adapter适配器模式的使用实例
2016/03/02 Python
django js实现部分页面刷新的示例代码
2018/05/28 Python
Python之两种模式的生产者消费者模型详解
2018/10/26 Python
Python使用sqlalchemy模块连接数据库操作示例
2019/03/13 Python
浅谈PYTHON 关于文件的操作
2019/03/19 Python
Python文件打开方式实例详解【a、a+、r+、w+区别】
2019/03/30 Python
Python递归函数 二分查找算法实现解析
2019/08/12 Python
python实现七段数码管和倒计时效果
2019/11/23 Python
pycharm 使用tab跳出正在编辑的括号(){}{}等问题
2021/02/26 Python
matplotlib阶梯图的实现(step())
2021/03/02 Python
详解利用css3的var()实现运行时改变scss的变量值
2021/03/02 HTML / CSS
app内嵌H5 webview 本地缓存问题的解决
2020/10/19 HTML / CSS
生物技术毕业生自荐信
2013/10/23 职场文书
活动策划求职信模板
2014/04/21 职场文书
工作分析计划书
2014/04/30 职场文书
python使用openpyxl库读写Excel表格的方法(增删改查操作)
2021/05/02 Python
LeetCode189轮转数组python示例
2022/08/05 Python