go sort包浅析
最近在刷leetcode,经常要使用sort包里面提供的查找和排序的函数,所以对其中使用比较多的方法做简单介绍。
首先是golang 标准库在线文档的索引 Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国 (studygolang.com)
1.排序
对于sort.Sort函数,它要求传入的数据类型实现下面这个接口
1 2 3 4 5 6 7 8 | type Interface interface { // Len方法返回集合中的元素个数 Len() int // Less方法报告索引i的元素是否比索引j的元素小 Less(i, j int) bool // Swap方法交换索引i和j的两个元素 Swap(i, j int) } |
sort包自带了对基本类型进行排序的函数,例如 Ints,Float64s, Strings等函数,一般直接调用就好。包里还自带了检查切片内数据是否已经排好序的函数,不再赘述。
sort 包在内部实现了四种基本的排序算法:插入排序(insertionSort)、归并排序(symMerge)、堆排序(heapSort)和快速排序(quickSort),sort.Sort会依据实际数据自动选择最优的排序算法(看了源码,比平常学习的快排要复杂不少,以后有空再看)。
而如果对排序结果的稳定性有要求,则考虑使用Stable这个函数(Stable先对每一小段元素插入排序,然后再进行整体的归并排序)。
默认排序完是递增排序,如果要递减排序,则可以借助Reverse这个函数,例如对[ ]int a进行递减排序,则调用 sort.Sort(sort.Reverse(sort.IntSlice(a)))
2.查找
查找算法的实现原理是二分查找(所以前提必须是有序)。需要注意的是,二分查找根据对等值元素应该返回哪个索引,又分为左边界二分查找,和右边界二分查找。
sort里的二分查找实现的就是左边界查找,即如果有相同的元素,则返回最左边那个元素的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | func Search(n int, f func (int) bool) int { // Define f(-1) == false and f(n) == true. // Invariant: f(i-1) == false, f(j) == true. i, j := 0, n for i < j { h := int(uint(i+j) >> 1) // avoid overflow when computing h // i ≤ h < j if !f(h) { i = h + 1 // preserves f(i-1) == false } else { j = h // preserves f(j) == true } } // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. return i } |
Search函数采用二分法搜索找到[0, n)区间内最小的满足f(i)==true的值i。也就是说,Search函数希望f在输入位于区间[0, n)的前面某部分(可以为空)时返回假,而在输入位于剩余至结尾的部分(可以为空)时返回真;Search函数会返回满足f(i)==true的最小值i。如果没有该值,函数会返回n。注意,未找到时的返回值不是-1,这一点和strings.Index等函数不同。Search函数只会用区间[0, n)内的值调用f。
一般使用Search找到值x在插入一个有序的、可索引的数据结构时,应插入的位置。这种情况下,参数f(通常是闭包)会捕捉应搜索的值和被查询的数据集。
例如,给定一个递增顺序的切片,调用Search(len(data), func(i int) bool { return data[i] >= 23 })会返回data中最小的索引i满足data[i] >= 23。如果调用者想要知道23是否在切片里,它必须另外检查data[i] == 23。
搜索递减顺序的数据时,应使用<=运算符代替>=运算符。
搜索右边界而非左边界时,则可把>=改为>,然后把Search函数的返回值减去1。
下列代码尝试在一个递增顺序的整数切片中找到值x:(注意search结束后,是如何对结果进行检查的)
1 2 3 4 5 6 7 8 | x := 23 i := sort.Search(len(data), func (i int) bool { return data[i] >= x }) if i < len(data) && data[i] == x { // x is present at data[i] } else { // x is not present in data, // but i is the index where it would be inserted. } |
如果没有自定义比较函数的需求,那么可以直接使用封装的函数sort.SearchInts 。同样的,不要忘记对结果的检查 if i < len(data) && data[i] == x
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了