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语言map与string的相互转换的实现
Apr 07 Golang
解决Golang中ResponseWriter的一个坑
Apr 27 Golang
golang 如何用反射reflect操作结构体
Apr 28 Golang
彻底理解golang中什么是nil
Apr 29 Golang
浅谈golang package中init方法的多处定义及运行顺序问题
May 06 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
Go 语言中 20 个占位符的整理
Oct 16 Golang
一文搞懂Golang 时间和日期相关函数
Dec 06 Golang
golang生成vcf通讯录格式文件详情
Mar 25 Golang
Go语言安装并操作redis的go-redis库
Apr 14 Golang
Golang 结构体数据集合
Apr 22 Golang
golang操作rocketmq的示例代码
Apr 06 #Golang
victoriaMetrics库布隆过滤器初始化及使用详解
如何解决goland,idea全局搜索快捷键失效问题
golang为什么要统一错误处理
简单聊聊Golang中defer预计算参数
Mar 25 #Golang
Go 中的空白标识符下划线
golang生成vcf通讯录格式文件详情
You might like
简单的页面缓冲技术
2006/10/09 PHP
用PHP查询搜索引擎排名位置的代码
2010/01/05 PHP
关于php mvc开发模式的感想
2011/06/28 PHP
PHP 第二节 数据类型之字符串类型
2012/04/28 PHP
浅析PHP关键词替换的类(避免重复替换,保留与还原原始链接)
2015/09/22 PHP
用JavaScript脚本实现Web页面信息交互
2006/10/11 Javascript
jQuery setTimeout()函数使用方法
2013/04/07 Javascript
JavaScript实现的in_array函数
2014/08/27 Javascript
javascript结合Flexbox简单实现滑动拼图游戏
2016/02/18 Javascript
JavaScript学习笔记之ES6数组方法
2016/03/25 Javascript
JS中的forEach、$.each、map方法推荐
2016/04/05 Javascript
JS获取IE版本号与HTML设置IE文档模式的方法
2016/10/09 Javascript
BootStrap table使用方法分析
2016/11/08 Javascript
AngularJS中指令的四种基本形式实例分析
2016/11/22 Javascript
Node.js实现连接mysql数据库功能示例
2017/09/15 Javascript
Vue组件中slot的用法
2018/01/30 Javascript
jQuery实现的下雪动画效果示例【附源码下载】
2018/02/02 jQuery
Angularjs实现控制器之间通信方式实例总结
2018/03/27 Javascript
使用Vue如何写一个双向数据绑定(面试常见)
2018/04/20 Javascript
原生JS 实现的input输入时表格过滤操作示例
2019/08/03 Javascript
layui table 多行删除(id获取)的方法
2019/09/12 Javascript
VUE前端从后台请求过来的数据进行转换数据结构操作
2020/11/11 Javascript
[12:51]71泪洒现场!是DOTA2让经典重现
2014/03/24 DOTA
[54:53]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第二场
2014/05/23 DOTA
[04:46]2018年度玩家喜爱的电竞媒体-完美盛典
2018/12/16 DOTA
Python中的Classes和Metaclasses详解
2015/04/02 Python
使用pandas对矢量化数据进行替换处理的方法
2018/04/11 Python
对numpy中数组转置的求解以及向量内积计算方法
2018/10/31 Python
python pymysql链接数据库查询结果转为Dataframe实例
2020/06/05 Python
解析python 中/ 和 % 和 //(地板除)
2020/06/28 Python
CSS3圆角边框和边界图片效果实例
2016/07/01 HTML / CSS
使用canvas绘制超炫时钟
2014/12/17 HTML / CSS
HTML5 video播放器全屏(fullScreen)方法实例
2015/04/24 HTML / CSS
中学生2014国庆节演讲稿:不屈的民族
2014/09/21 职场文书
2014年车间工作总结
2014/11/21 职场文书
Python基础详解之描述符
2021/04/28 Python