第二十九章 排序(sort)

作者:李骁

29.1 sort包介绍

Go语言标准库sort包中实现了几种基本的排序算法:插入排序、快排和堆排序,但在使用sort包进行排序时无需具体考虑使用那种排序方式。

func insertionSort(data Interface, a, b int) 
func heapSort(data Interface, a, b int)
func quickSort(data Interface, a, b, maxDepth int)

sort.Interface接口定义了三个方法,注意sort包中接口Interface这个名字,是大写字母I开头,不要和interface关键字混淆,这里就是一个接口名而已。

type Interface interface {
    // Len 为集合内元素的总数  
    Len() int
    // 如果index为i的元素小于index为j的元素,则返回true,否则false
    Less(i, j int) bool
    // Swap 交换索引为 i 和 j 的元素
    Swap(i, j int)
}

这三个方法分别是:获取数据集合长度的Len()方法、比较两个元素大小的Less()方法和交换两个元素位置的Swap()方法。只要实现了这三个方法,就可以对数据集合进行排序,sort包会根据实际数据自动选择高效的排序算法。

sort包原生支持[]int、[]float64和[]string三种内建数据类型切片的排序操作,即不必我们自己实现相关的Len()、Less()和Swap()方法。

以[]int为例,我们看看在sort包中的是怎么定义排序操作的:

type IntSlice []int

先通过 []int 来定义新类型IntSlice,然后在IntSlice上定义三个方法,Len(),Less(i, j int),Swap(i, j int),实现了这三个方法也就意味着实现了sort.Interface。

方法 func (p IntSlice) Sort() 通过调用 sort.Sort(p) 函数来实现排序。而p因为是sort.Interface类型,但IntSlice实现了这三个接口方法,也是sort.Interface类型,因此可以直接调用得到排序结果。其他[]float64和[]string的排序也基本上按照这种方式来实现。

其他类型并没有在标准包中给出实现方法,需要我们自己来定义实现。下面第二节 自定义sort.Interface排序 就是专门来讲怎么实现的,但有了这三个实现的实例,自定义实现排序也就很容易了。

来看看[]int,[]string排序的实例:

默认结果都是升序排列,如果我们想对一个 sortable object 进行逆序排序,可以自定义一个type。但 sort.Reverse 帮你省掉了这些代码。

相关方法:

29.2 自定义sort.Interface排序

如果是具体的某个结构体的排序,就需要自己实现Interface了。数据集合(包括自定义数据类型的集合)排序需要实现sort.Interface接口的三个方法,即:Len(),Swap(i, j int),Less(i, j int),数据集合实现了这三个方法后,即可调用该包的Sort()方法进行排序。Sort(data Interface) 方法内部会使用quickSort()来进行集合的排序。quickSort()会根据实际情况来选择排序方法。

任何实现了 sort.Interface 的类型(一般为集合),均可使用该包中的方法进行排序。这些方法要求集合内列出元素的索引为整数。

该示例程序的自定义类型personSlice实现了sort.Interface接口,所以可以将其对象作为sort.Sort()和sort.Stable()的参数传入。运行结果:

29.3 sort.Slice

利用sort.Slice 函数,而不用提供一个特定的 sort.Interface 的实现,而是 Less(i,j int) 作为一个比较回调函数,可以简单地传递给 sort.Slice 进行排序。这种方法一般不建议使用,因为在sort.Slice中使用了reflect。

目录

第二十八章 unsafe包

第三十章 OS包

本书《Go语言四十二章经》内容在github上同步地址:https://github.com/ffhelicopter/Go42

虽然本书中例子都经过实际运行,但难免出现错误和不足之处,烦请您指出;如有建议也欢迎交流。 联系邮箱:[email protected]

Last updated

Was this helpful?