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

 

posted @   布羽  阅读(248)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示