-
排序算法是一种能将一系列数据按照特定顺序进行排列的算法,比如说一个学校的考试分数从高到低排名、一个公司的数据报表从大到小排列,都需要用到排序算法。常见的排序算法有冒泡排序、快速排序、字典排序、归并排序、堆排序等等,而归并排序是其中的一种较为稳定、高效的排序算法,时间复杂度N*log2N。 本文通过Go语言开源社区的归并排序算法优化案例为例,讲解通用的算法分析、优化方法。1. Go语言的归并排序算法Go语言的sort包对插入排序、归并排序、快速排序、堆排序做了支持,归并排序是sort包实现的稳定排序算法。 Go语言基于递归实现了归并排序算法,代码如下:// 优化前的归并排序代码,使用递归实现两个有序子序列data[a:m]和data [m:b]的合并func symMerge(data Interface, a, m, b int) { // 初始化mid,start,r的值,mid表示[a:b]的中位数,start表示[a:m]区间进行数据交换的开始下标,r表示[a:m]区间进行数据交换的最右下标 mid := int(uint(a+b) >> 1) n := mid + m var start, r int if m > mid { start = n - b r = mid } else { start = a r = m } p := n - 1 // 折半查找对称比较数据块[a:m]和数据块[m:b],找出数据块[a:m]开始大于数据[m:b]的下标位置start for start < r { c := int(uint(start+r) >> 1) if !data.Less(p-c, c) { start = c + 1 } else { r = c } } // 翻转数据块[start:m] 和 [m:end], 使得数据块[start:end]有序 end := n - start if start < m && m < end { rotate(data, start, m, end) } // 调用递归函数,排序两组子数据块[a:start]和[start:mid],[mid:end]和[end:b] if a < start && start < mid { symMerge(data, a, start, mid) } if mid < end && end < b { symMerge(data, mid, end, b) }}2. 场景及问题分析归并排序算法的应用场景主要是数据块有序归并,比如说有序切片data[0:20]和data[20:40]的合并有序场景,主要处理过程如下:1. 调用递归函数symMerge,初始化切片参数。2. 经过折半查找、对称比较、翻转等方法使得切片data[0:20]整体小于切片data[20:40]3. 再次调用递归函数symMerge归并排序子切片data[0:start]和data[start:20],回到步骤14. 再次调用递归函数symMerge归并排序子切片data[20:end]和data[end:40],回到步骤15. 直到排序完所有的子切片,使得整个切片data[0:40]有序。从这个常见的应用场景的处理过程中发现,归并排序需要不断调用递归函数处理子序列,而这也是归并排序算法的性能损耗的主要原因。在切片的归并排序场景中,如果能避免或减少调用递归处理子切片,算法的运行性能就可以得到提升。比如说在长度为1的子切片data[0]和长度为9的子切片data[1:10]进行归并排序的场景下,使用插入排序来避免调用递归,可以减少算法的运行耗时,优化算法的性能。3. 优化方案及实现通过上述对Go语言归并排序算法的代码和场景分析,找到了一种优化方法,即在归并排序中,针对长度为1的数据块,利用二分插入排序算法处理数据块排序,可以减少函数递归的调用,提高算法的性能。 Go语言开源社区也应用了基于二分插入排序的优化方法,提升了归并排序算法的性能,优化前后的代码对比如下: 优化代码如下:// 优化代码增加了对切片长度的判断,且当切片长度为1时,使用二分插入排序直接排序切片返回。func symMerge(data Interface, a, m, b int) { // data[a:m]只有一个元素时,使用二分插入排序找到有序的插入点,插入data[a]到data[m:b] // 避免调用递归,提高算法性能 if m-a == 1 { i := m j := b // 二分查找,找到合适的有序插入点 for i < j { h := int(uint(i+j) >> 1) if data.Less(h, a) { i = h + 1 } else { j = h } } // 插入数据 for k := a; k < i-1; k++ { data.Swap(k, k+1) } return } // data[m:b]只有一个元素时,使用二分插入排序找到合适的有序插入点,插入data[m]到data[a:m] // 避免调用递归,提高算法性能 if b-m == 1 { i := a j := m // 二分查找,找到合适的有序插入点 for i < j { h := int(uint(i+j) >> 1) if !data.Less(m, h) { i = h + 1 } else { j = h } } // 插入数据 for k := m; k > i; k-- { data.Swap(k, k-1) } return } // 归并排序的递归实现 ......}4. 优化结果使用Go benchmark测试优化前后的算法性能,再用Go benchstat对比优化前后的性能测试结果,并统计了优化前后递归函数的调用次数,整理到如下表格:测试项测试用例优化前每操作耗时 time/op优化后每操作耗时 time/op耗时对比优化前递归总次数优化后递归总次数递归总次数对比BenchmarkStableString1K-8长度1K的字符串切片302278 ns/op288879 ns/op-2.71%1110790-28.8%BenchmarkStableInt1K-8长度1K的整型切片144207 ns/op139911 ns/op-0.96%689586-14.9%BenchmarkStableInt64K-8长度64K的整型切片12291195 ns/op12119536 ns/op-0.75%4846541280-14.8%BenchmarkStable1e2-8长度1e2(100)的结构体切片135357 ns/op124875 ns/op-7.17%1079807-25.2%BenchmarkStable1e4-8长度1e4(10000)的结构体切片43507732 ns/op40183173 ns/op-7.64%449735350205-22.1%BenchmarkStable1e6-8长度1e6(1000000)的结构体切片9005038733 ns/op8440007994 ns/op-7.69%7934784361483110-22.5%[注] -8表示函数运行时的GOMAXPROCS值,ns/op表示函数每次执行的平均纳秒耗时。上述表格显示了在字符串切片、整型切片、结构体切片等不同数据类型的场景下的性能测试结果,对比分析如下:• 对比长度为1K的字符串和整型切片数据,优化后字符串切片的递归次数减少了28.8%,而整型切片的递归次数只减少了14.9%,说明优化技术在字符串切片数据集上发挥了更大的作用,性能提升更大;• 对比长度为64K和1K的整型切片数据,优化后二者的递归总次数减少的比例都在14.8%左右,性能提升相近在0.5%-1%之间;• 对比长度为1e2e4e6的结构体切片数据,优化后三者的递归总次数都减少在22%左右,性能提升基本一样在7%左右。通过性能测试结果的对比分析,发现优化后的性能提升大小跟测试数据集的关联性大,算法的递归嵌套中出现数据切片长度为1的情况越多,优化方法发挥的作用就越大,递归次数减少的更多,性能提升也会更大。5. 总结Go语言的归并排序算法优化案例,从一个具体的场景出发分析归并排序算法存在的性能问题,给出了基于二分插入排序的优化方案,并最终验证了优化结果,是一个值得学习借鉴的算法优化实践。
-
2020-12-18:java和go,并发控制有哪几种方式?#福大大架构师每日一题#
-
2020-12-17:java和go,如何高效的拼接字符串?#福大大架构师每日一题#
-
那晚你错过的交流(PPT文末自取)那一晚,你没来第八期云享MindTalks,可能错过了一场精彩的对话交流~餐前小甜点助手小采访:你为什么选择用Python?因为语法简单?优雅?还是因为免费?:不,因为惜命,“人生苦短,我用Python”。暖心小贴士:Python的编写效率高,可以用Python省下的时间去植发哦。助手小采访:用Python你幸福吗?:我姓张。助手小采访:……,那可以请您简单分享一下Python的使用体验吗?:动态一时爽,一直动态一直爽。助手小采访:那是不是意味着这个工具很好用,妈妈再也不用担心我出bug的感觉?:什么BUG?!!暖心小贴士:动态一时爽,重构火葬场,这是动态语言的弊端。助手小采访:听说您之后又去学了Go?请用一句话证明。:err !=nil精彩正餐吃到饱交流者1号:Go的gorotine和Python的corotine区别?张老师:gorotine应该就是Go语言的协程,corotine是Python语言的协程,corontine是借鉴了JavaScript里的语法。协程你可以想象为轻量型的线程。交流者2号:我现在想修全栈向,Python用了三年,不会别的语言。一直在开脚本和API,想做点带前端的完整作品。未来趋势来看,是修炼react+go还是继续Python撸flask+django?张老师:谈点个人看法啊,Python用了三年说明你已经很熟悉Python了。从我自己的经历来说,我也是先学了Python然后又学习了Go,我觉得我们学点其他的知识,有助于拓宽我们的知识面,能够帮助到自己打开视野。react是Javascript的一个分支,一个框架,如果你想要修全栈的话,是可以学习一下的。现在react,vue比较主流,flask的话,目前不是那么的主流。交流者3号:Python使用uvloop的话,速度比Go如何?张老师:这个问题我没有实践过uvloop,无法给你做准确的判断,如果你用Python做一些底层的设计的话,能够对它进行一些优化,很可能会取得很好的效果。交流者4号:前端是vue还是react?如果时间有限的话。张老师:国内的话vue还是很多的,国外多是react,如果时间有限的话,建议学习vue,可以从3开始学;如果时间允许的话,建议两个都可以学着看看。交流者5号:Python转数据挖掘可以吗?不知道从何下手。张老师:如果你是用Python做数据分析,是完全可以转数据挖掘的。数据挖掘的话,还包含数据分析和机器学习的,Python的话,比较好的一点,就是有很多库都给你封装好了。如果说你能理解基础原理的话,完全是可以转的。交流者6号:Go和dart差不多吗?张老师:我知道移动端一个比较火的框架就是用dart语言写的,dart的话更多的可能会用于移动开发,相对来说Go的话使用的范围更广。交流者7号:老师是怎么学习Go的?张老师:总结下来的话,就是实践,“实践出真理”,我觉得我个人比较有效的学习方式就是通过实践,因为有Python的基础,经常做Python和go的对比,加强自己的理解,也更有意思。learn by doing是非常有效的学习方式。交流者8号:老师您的CrawLab从Python到Go重构了多久?张老师:重构了大概二十天左右,最近在着手做大的架构升级,预计明年初可以发版~Github: https://github.com/crawlab-team/crawlabDemo: https://demo-pro.crawlab.cn文档: https://docs.crawlab.cn欢迎大家来给我+star哦~谢谢交流者9号:请问有什么推荐的项目吗?张老师:推荐可以从小项目入手,比如: PPT: https://tinyurl.com/yd7gdf4k- 视频: https://www.bilibili.com/video/BV1Az4y1r7gE/- Go入门开源项目: 1. https://github.com/linxGnu/goseaweedfs 2. https://github.com/spf13/viper 3. https://github.com/crawlab-team/crawlab-go-sdk 4. https://github.com/jaeles-project/gospider学习资料推荐Python 基础 •https://github.com/jackfrued/Python-Core-50-Courses (中文) •https://github.com/learnbyexample/Python_Basics (英文) 进阶 《Python高性能编程》 - Micha Gorelick & Ian Ozsvald 《Python核心编程》 - Wesley Chun 《利用Python进行数据分析》 - Wes McKinney 《Python自然语言处理》 - Steven Bird, Ewan Klein & Edward Loper 《Python 3网络爬虫开发实战》 - 崔庆才 《Python 3网络爬虫宝典》 - 韦世东 极客时间《Python核心技术与实战》 -景霄Go 基础 掘金小册《基于 Go 语言构建企业级的 RESTful API 服务》 - 雷克斯 《Go语言核心编程》 - 李文塔 进阶 《Go语言实战》 - William Kennedy, Brian Ketelsen & Erik St. Martin 《Go语言高级编程》 - 柴树杉 &曹春晖更多精彩,敬请期待~扫码进微信群,仅限200人开始时间12月17日 20:00活动介绍云享MindTalks是由华为云DevCloud团队携手云享专家共同策划进行的系列技术交流活动。各业界大咖纷纷现身群聊,以即时对话形式,来进行最直接的技术交流和思想碰撞。不同领域的专家,各样的业界话题尽在此处,为保证极简极高效,活动仅20分钟,限量200人,先进先得。编程语言那么多那个才是你的心头好?是优雅简单的Python?还是高效精致的Go?动态与静态语言的选型之争,由张冶青老师带你全面分析! 专家介绍知名外企前端开发工程师神秘Night Team(夜幕团队)成员8年软件开发经验,全干工程师专注前端、爬虫和数据分析领域活动规则1.扫码加小助手入群聊,仅限200人,先到先得。2.对未能及时回复的问题,由助手收集集中回答。3.更多资源和活动请进入云享MindTalks VIP群。4.抽奖奖品为限定HE2E知识卡牌和老师推荐书籍 《Go语言核心编程》。
-
2020-12-12:现场写代码,把CPU打满,java和go都行,并解释为什么。#福大大架构师每日一题#
-
不玩虚,才是真狂欢,扫描图中二维码,火力全开“购够GO”!!!------【我】------【是】------【分】------【割】------【线】---【学习福利】关注华为云GaussDB(DWS)公众号:这里会定期推送相关干货:精品博文、维护宝典、产品信息等,和您分享最新最全的PB级数仓GaussDB(DWS)黑科技~(扫描下方公众号二维码即可关注)添加华为云GaussDB(DWS)小助手微信号:进入专家交流群,实时交流学习、分享最新的DWS资源~(扫描下方小助手二维码即可进群)GaussDB(DWS)产品主页:https://www.huaweicloud.com/product/dws.html
-
https://bbs.huaweicloud.com/forum/thread-92792-1-1.html
-
2020-12-07:go中,slice的底层数据结构是什么?#福大大架构师每日一题#
-
2020-12-05:go中,map的扩容流程是什么?#福大大架构师每日一题#
-
2020-11-28:go中,map的写流程是什么?#福大大架构师每日一题#
-
2020-11-27:go中,map的读流程是什么?#福大大架构师每日一题#
-
2020-11-26:go中,map的创建流程是什么?#福大大架构师每日一题#
-
2020-11-25:go中,map的底层数据结构是什么?#福大大架构师每日一题#
-
GO语言一张白纸,从CloudIDE开始,也算是云原生了吧。学习一门语言,最好的方法直接是上代码,搜了下没找到最佳实践,就从csdn上找到些例子:package main import "fmt" func main() { var line int = 10 //行数 for i := 0; i < line-1; i++ { for j := 0; j < line-i-1; j++ { fmt.Print(" ") } for k := 0; k < i*2+1; k++ { fmt.Print("*") } fmt.Println() }}跑了下,问题就来了。。。。显示不对呀,但是哪里有问题呢?改个line=9那就是10不对么?第三遍运行:这。。。哪里有问题了呢?
-
2020-11-23:go中,s是一个字符串,s[0]代表什么?是否等于固定字节数?#福大大架构师每日一题#
上滑加载中
推荐直播
-
空中宣讲会 2025年华为软件精英挑战赛
2025/03/10 周一 18:00-19:00
宸睿 华为云存储技术专家、ACM-ICPC WorldFinal经验 晖哥
2025华为软挑赛空中宣讲会重磅来袭!完整赛程首曝+命题天团硬核拆题+三轮幸运抽奖赢参赛助力礼包,与全国优秀高校开发者同台竞技,直通顶尖赛事起跑线!
回顾中 -
华为开发者空间玩转DeepSeek
2025/03/13 周四 19:00-20:30
马欣 华为开发者布道师
同学们,想知道如何利用华为开发者空间部署自己的DeepSeek模型吗?想了解如何用DeepSeek在云主机上探索好玩的应用吗?想探讨如何利用DeepSeek在自己的专有云主机上辅助编程吗?让我们来一场云和AI的盛宴。
即将直播 -
华为云Metastudio×DeepSeek与RAG检索优化分享
2025/03/14 周五 16:00-17:30
大海 华为云学堂技术讲师 Cocl 华为云学堂技术讲师
本次直播将带来DeepSeek数字人解决方案,以及如何使用Embedding与Rerank实现检索优化实践,为开发者与企业提供参考,助力场景落地。
去报名
热门标签