go排序

141 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

1. sort包介绍

Go语言标准库sort包中实现了3种基本的排序算法:插入排序、快排和堆排序。和其他语言中一样,这三种方式都是不公开的,他们只在sort包内部使用。所以用户在使用sort包进行排序时无需考虑使用那种排序方式,sort.Interface定义的三个方法:获取数据集合长度的Len()方法、比较两个元素大小的Less()方法和交换两个元素位置的Swap()方法,就可以顺利对数据集合进行排序。sort包会根据实际数据自动选择高效的排序算法。

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

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

package main
import (
    "fmt"
    "sort"
)
func main() {
    a := []int{3, 5, 4, -1, 9, 11, -14}
    sort.Ints(a)
    fmt.Println(a)
    ss := []string{"surface", "ipad", "mac pro", "mac air", "think pad", "idea pad"}
    sort.Strings(ss)
    fmt.Println(ss)
    sort.Sort(sort.Reverse(sort.StringSlice(ss)))
    fmt.Printf("After reverse: %v\n", ss)
}

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

package main
import (
    "fmt"
    "sort"
)
func main() {
    a := []int{4, 3, 2, 1, 5, 9, 8, 7, 6}
    sort.Sort(sort.Reverse(sort.IntSlice(a)))
    fmt.Println("After reversed: ", a)
}
  • 将类型为float64的slice以升序方式排序 func Float64s(a []float64)
  • 判定是否已经进行排序func Ints(a []int) func Float64sAreSorted(a []float64) bool 
  • Ints 以升序排列 int 切片。 func Ints(a []int)
  • 判断 int 切片是否已经按升序排列。 func IntsAreSorted(a []int) bool 
  • IsSorted 判断数据是否已经排序。包括各种可sort的数据类型的判断. func IsSorted(data Interface) bool
  • Strings 以升序排列 string 切片。 func Strings(a []string)
  • 判断 string 切片是否按升序排列 func StringsAreSorted(a []string) bool
  • search使用二分法进行查找,Search()方法回使用“二分查找”算法来搜索某指定切片[0:n], 并返回能够使f(i)=true的最小的i(0<=i<n)值,并且会假定,如果f(i)=true,则f(i+1)=true
  • 即对于切片[0:n],i之前的切片元素会使f()函数返回false,i及i之后的元素会使f()函数返回true。但是,当在切片中无法找到时f(i)=true的i时(此时切片元素都不能使f()函数返回true),Search()方法会返回n(而不是返回-1)

2. 自定义sort.Interface排序

如果是具体的某个结构体的排序,就需要自己实现Interface了。

package main
import (
    "fmt"
    "sort"
)
type person struct {
    Name string
    Age  int
}
type personSlice []person
func (s personSlice) Len() int           { return len(s) }
func (s personSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s personSlice) Less(i, j int) bool { return s[i].Age < s[j].Age }
func main() {
    a := personSlice{
        {
            Name: "AAA", 
            Age:  55, 
        }, 
        {
            Name: "BBB", 
            Age:  22, 
        }, 
        {
            Name: "CCC", 
            Age:  0, 
        }, 
        {
            Name: "DDD", 
            Age:  22, 
        }, 
        {
            Name: "EEE", 
            Age:  11, 
        }, 
    }
    sort.Sort(a)
    fmt.Println("Sort:", a)
    sort.Stable(a)
    fmt.Println("Stable:", a)
}

3. sort.Slice

利用sort.Slice 函数,而不用提供一个特定的 sort.Interface 的实现,而是 Less(i,j int) 作为一个比较回调函数,可以简单地传递给 sort.Slice 进行排序。

package main
import (
    "fmt"
    "sort"
)
type Peak struct {
    Name      string
    Elevation int // in feet
}
func main() {
    peaks := []Peak{
        {"Aconcagua", 22838}, 
        {"Denali", 20322}, 
        {"Kilimanjaro", 19341}, 
        {"Mount Elbrus", 18510}, 
        {"Mount Everest", 29029}, 
        {"Mount Kosciuszko", 7310}, 
        {"Mount Vinson", 16050}, 
        {"Puncak Jaya", 16024}, 
    }
    // does an in-place sort on the peaks slice, with tallest peak first
    sort.Slice(peaks, func(i, j int) bool {
        return peaks[i].Elevation >= peaks[j].Elevation
    })
    fmt.Println(peaks)
}