Go sort.Sort、sort.Reverse源码阅读有感

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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值