10.15. sort

排序算法是常见的算法,内置库实现了插入排序、归并排序、堆排序和快速排序,有几种排序算法是不可直接访问的,需要使用内置的库来访问,因此使用过程中无须关心使用了哪种排序算法。

内置库提供了对常见数据类型的排序。排序包含如下操作:

  • 升序、降序。

  • 是否排序。

  • 对任意数据类型进行排序。

对数值类型的数组进行排序很容易理解,如何对结构体进行排序呢?结构体中包含多个属性或者字段,对结构体排序时,应该按照某一个属性或者字段进行排序,否则无法比较。

内置库也提供了相应的接口,实现对任意数据类型的排序,如图

../../_images/image-20220707135611475.png

10.15.1. 1. 整数类型数值的排序

func SortIntsUsage() {
    list := []int{10, 9, 2, 8, 3}
    sort.Ints(list)
    fmt.Println(list)   // [2 3 8 9 10]
    sort.Sort(sort.Reverse(sort.IntSlice(list)))
    fmt.Println(list)   // [10 9 8 3 2]
}

10.15.2. 2. 浮点类型数值的排序

func SortFloatsUsage() {
    list := []float64{10, 9, 1.2, 3.4, 12.1}
    sort.Float64s(list)
    fmt.Println(list)       // [1.2 3.4 9 10 12.1]
    sort.Sort(sort.Reverse(sort.Float64Slice(list)))
    fmt.Println(list)       // [12.1 10 9 3.4 1.2]
}

10.15.3. 3. 字符串类型数值的排序

func SortStringsUsage() {
    list := []string{"a", "A", "c", "C", "B", "b"}
    sort.Strings(list)
    fmt.Println(list)   // [A B C a b c]
    sort.Sort(sort.Reverse(sort.StringSlice(list)))
    fmt.Println(list)   // [c b a C B A]
}

字符串按照首字母的ASCII编码进行排序。

可以很方便地实现对内置基本类型的排序,如何对任意类型(比如复杂的结构体)进行排序呢?

答案是实现Interface接口。

type Interface interface {
    // Len is the number of elements in the collection.
    Len() int

    // Less reports whether the element with index i
    // must sort before the element with index j.
    Less(i, j int) bool

    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

要实现Interface接口,就需要实现Len、Less、Swap三个方法。

package main

import (
    "fmt"
    "sort"
)

type Language struct {
    Year    int    `json:"year"`
    Name    string `json:"name"`
    Account string `json:"account"`
}

type Languages []Language

func (ls Languages) Len() int {
    return len(ls)
}
func (ls Languages) Less(i, j int) bool {
    return ls[i].Year < ls[j].Year
}
func (ls Languages) Swap(i, j int) {
    ls[i], ls[j] = ls[j], ls[i]
}

func SortStruct() {
    list := Languages{
        {
            10, "Golang", "Google",
        }, {
            28, "Python", "Google",
        }, {
            30, "Java", "***",
        }, {
            1, "Lua", "23",
        },
    }
    fmt.Println("Ori", list)
    sort.Sort(list)
    fmt.Println("sort", list)
    for _, i := range list {
        fmt.Println(i)
    }
}

func main() {
    SortStruct()
}

自定义的结构体Languages按照字段Year从小到大排序,开发者实现Interface接口即可。

再回过头来看如何排序内置的基本数据类型。

// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
type IntSlice []int
func (x IntSlice) Len() int           { return len(x) }
func (x IntSlice) Less(i, j int) bool { return x[i] < x[j] }
func (x IntSlice) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }


type Float64Slice []float64
func (x Float64Slice) Len() int { return len(x) }
func (x Float64Slice) Less(i, j int) bool { return x[i] < x[j] || (isNaN(x[i]) && !isNaN(x[j])) }
func (x Float64Slice) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }


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

由此可以看出,内置的基本数据类型已经实现了Interface接口。

同样的,浮点类型、字符串类型也实现了Interface接口。

10.15.4. 4.sort -排序算法

https://www.topgoer.cn/docs/golangstandard/golangstandard-1cmksspljkkud

10.15.5. 5. 小结

内置的排序库可以很方便地让开发者实现对基本数据类型的排序,或者对自定义结构体按照某一个字段进行排序,只要实现Interface接口即可。

而使用者无须关心内置库到底使用了哪种排序算法。