golang sort包解析(一)

Go语言的sort.Sort函数不会对具体的序列和它的元素做任何假设。相反,它使用了一个接口类型sort.Interface来指定通用的排序算法和可能被排序到的序列类型之间的约定。与c++中标准库的函数类似,sort包提供的函数也属于泛型函数。

接口定义

type Interface interface {
	Len() int
	Less(i, j int) bool
	Swap(i, j int)
}

与c++和java等语言不通的是,golang的继承不需要显示指明基类或接口类。只要类型实现了接口的方法,类型和接口自动就关联起来。这样做带来的另一个不同点是,我们可以先实现类型,再提供接口。

主函数

func Sort(data Interface) {
	n := data.Len()
	quickSort(data, 0, n, maxDepth(n))
}

从C++语言过来的程序员可能会比较不适应,因为c++提供的标准库是可以直接操作像vector,list这样的数组模版的。Golang的slice没有Interface所需的方法,因此必须对其进行处理后才能使用Sort函数。

比如

type StringSlice []string
func (p StringSlice) Len() int           { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

这里有个思想上的转变。

str_list = {"aa","bb","cc"}
sort.Sort(StringSlice(str_list))

虽然对于str_list进行了一次类型转换,从[]string转换到了新定义的StringSlice,但转换后的变量仍与之前的变量共享底层数据,它们都是指向同一个array数组。因此对于转换后的变量进行排序后,原先的slice也有序了。

看另一个例子

type customSort struct {
    t    []*Track
    less func(x, y *Track) bool
}

func (x customSort) Len() int
func (x customSort) Less(i, j int) bool { return x.less(x.t[i], x.t[j]) }
func (x customSort) Swap(i, j int)      { x.t[i], x.t[j] = x.t[j], x.t[i] }

我们看到customSort类型提供sort.Interface所需要的方法,因此可以被sort.Sort调用。customSort是一个struct类型,需要排序的数据接口是其内部的成员t,它是一个slice。因此对于customSort类型的变量进行排序,其结果是对成员t进行的排序。这里的另一个细节是使用slice pointer,移动指针比对象的效率更高,个人认为这也是一个语法糖,可以这么进行初始化:

var tracks = []*Track{
	{"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
	{"Go", "Moby", "Moby", 1992, length("3m37s")},
	{"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
	{"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
}

Reverse函数

sort包中提供了Reverse函数将排序顺序转换成逆序,他是这么使用的:

sort.Sort(sort.Reverse(byArtist(tracks)))

我们看一下和Reverse相关的代码:

ype reverse struct{ Interface } // that is, sort.Interface
func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }
func Reverse(data Interface) Interface { return reverse{data} }

Reverse函数接受一个Interface实例,这里有一个隐式的structinterface的转换。在函数的body里,它被赋值到reverse结构体中的成员里,返回时又有一次reverse结构体到Interface接口的转换。之所以能这样转换,是因为reverse结构体也(隐式的)实现了Interface所需的方法。所有的拷贝转换之所以成行(排序结果生效),是因为slice的拷贝属于引用拷贝。

常用函数

考虑到[]int, []float64,[]string在排序中经常会被使用到,sort包提供了相应的类型对齐进行转化(IntSlice,Float64Slice,StringSlice),这样我们可以直接使用sort.Ints,sort.Float64s,sort.Strings进行排序处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值