sort
- sort 是Golang提供的封装了排序功能的库。
- 其中提供了一些常用的便捷排序方法,也通过接口类型,为用户提供自定义排序的功能
便捷方法:
sort.Ints
func Ints(x []int) { Sort(IntSlice(x)) }
sort.Float64s
func Float64s(x []float64) { Sort(Float64Slice(x)) }
sort.Strings
func Strings(x []string) { Sort(StringSlice(x)) }
上述三个方法的使用方式都是传入对应的切片类型即可,我们可以看见它们的具体实现都复用了 Sort方法
,我觉得这是 sort 库最巧妙的地方
实现原理
Golang将排序算法提炼为三个要素:序列长度Len()
、两个元素的比较结果Less()
、两个元素的交换方法Swap()
,只要用户定义的类型实现了这三个方法,就可以复用它提供的排序功能,sort库内部会根据实际情况,对不同数据自动选择最优的排序算法!
它是如何实现的呢?
Interface类型
type Interface interface {
Len() int
Less(i, j int) boo
Swap(i, j int)
}
func Sort(data Interface) {
n := data.Len()
if n <= 1 {
return
}
limit := bits.Len(uint(n))
pdqsort(data, 0, n, limit)
}
Interface是一个接口类型,我们的自定义类型实现了sort.interface接口后
就可以用 Interface 类型 指向自定义类型,然后调用 sort.Sort 方法(也就是多态,Golang的多态真的蛮奇妙的)
Sort方法复用了 pdqsort 方法,实现了先前所说的“根据实际情况,自动选择最优排序算法”
sort.Reverse方法 (注意这个方法是指按降序排序)
相比起其他语言的算法库,Golang的 Reverse 方法使用较为麻烦,如下所示:
type intSlice []int
// 实现Interface类型的三个方法
// 比起说实现接口,我更喜欢说实现该类型的全部方法,因为接口类型本身就是一种数据类型
func (p intSlice) Len() int { return len(p) }
func (p intSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p intSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func main() {
nums := intSlice{3, 2, 1, 8, 9}
sort.Sort(sort.Reverse(nums))
fmt.Println(nums)
}
先看一下 sort库中的 reverse
结构体
type reverse struct {
// 相当于继承了一个匿名的Interface类型
// 也就是直接复用了 Interface接口的方法
Interface
}
// 重新定义 Less 方法,这点很重要,相当于把Less方法替换为升序
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
简单来说,sort库 通过一个继承了【Interface类型】的 【reverse 结构体】,重写了它的Less方法,然后通过对外的 Reverse方法来给用户 返回一个 Interface类型
func Reverse(data Interface) Interface {
return &reverse{data}
}
// 再来看一下 Sort
func Sort(data Interface) {
n := data.Len()
if n <= 1 {
return
}
limit := bits.Len(uint(n))
pdqsort(data, 0, n, limit)
}
我们通过Reverse方法来获得一个 Interface类型,用它指向用户自定义类型,然后将待排序数据传递给 Sort方法,就可以完成排序了
// 也就是这一步
sort.Sort(sort.Reverse(nums))
sort.Slice排序
Go 1.8后实现了 sort.Slice
方法,这个方法特别轻便!只需要我们提供一个排序时对元素的回调函数即可
// 降序排序的传统方法
type intSlice []int
func (p intSlice) Len() int { return len(p) }
func (p intSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p intSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func main() {
nums := intSlice{3, 2, 1, 8, 9}
sort.Sort(sort.Reverse(nums))
fmt.Println(nums)
}
// sort.Slice
nums := []int{3, 2, 1, 8, 9}
sort.Slice(nums, func(i, j int) bool {
return nums[i] > nums[j]
})
fmt.Println(nums)