• Go 语言标准库之 sort 包


    sort 包实现了四种基本排序算法:插入排序(希尔排序)、归并排序、堆排序和快速排序,这四种排序方法是不公开的,它们只被用于 sort 包内部使用。在实际使用中,对数据集合排序时不必考虑应当选择哪一种排序方法,sort 包会根据实际数据自动选择高效的排序算法。

    sort.Interface 接口

    实现了sort.interface的类型(一般为集合),都可以使用 sort 包中函数进行排序 ,sort.Interface接口定义如下:

    type Interface interface {
        // Len 方法返回集合中的元素个数
        Len() int
        // Less 方法报告索引 i 的元素是否比索引 j 的元素小
        Less(i, j int) bool
        // Swap 方法交换索引 i 和 j 的两个元素
        Swap(i, j int)
    }
    

    自定义类型排序

    Sort/Stable 函数

    // 对 data 进行排序,不保证稳定性,即相等元素的相对次序可能改变
    // Sort 调用 1 次 data.Len 确定长度,调用 O(n*log(n)) 次 data.Less 和 data.Swap
    func Sort(data Interface)
    
    // 对 data 进行排序,保证排序的稳定性,即相等元素的相对次序不变
    // Sort 调用 1 次 data.Len,O(n*log(n)) 次 data.Less 和 O(n*log(n)*log(n)) 次 data.Swap
    func Stable(data Interface)
    
    // 包装一个 sort.Interface 接口并返回一个新的 sort.Interface 接口,对该接口排序可生成递减序列
    func Reverse(data Interface) Interface
    
    // 判断 data 是否已经被排序
    func IsSorted(data Interface) bool
    

    ☕️ 示例代码

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    type Student struct {
        Name string
        Age  int
    }
    
    type StudentSlice []Student
    
    // 实现 sort.Interface 接口
    func (ss StudentSlice) Len() int {
        return len(ss)
    }
    
    func (ss StudentSlice) Less(i, j int) bool {
        return ss[i].Age < ss[j].Age
    }
    
    func (ss StudentSlice) Swap(i, j int) {
        ss[i], ss[j] = ss[j], ss[i]
    }
    
    func main() {
        ss := StudentSlice{
            {"Alice", 18},
            {"Bob", 20},
            {"Allen", 16},
            {"Michelle", 18},
            {"James", 24},
        }
        // 按照年龄递增排序
        sort.Sort(ss)
        fmt.Println(ss) // [{Allen 16} {Alice 18} {Michelle 18} {Bob 20} {James 24}]
        // 判断是否已经被排序
        fmt.Println(sort.IsSorted(ss)) // true
    
        // 按照年龄递减排序
        sort.Sort(sort.Reverse(ss))
        fmt.Println(ss) // [{James 24} {Bob 20} {Alice 18} {Michelle 18} {Allen 16}]
        // 判断是否已经被排序
        fmt.Println(sort.IsSorted(ss)) // false
    }
    

    Slice/SliceStable 函数

    在前面Sort/Stable函数的排序中,自定义类型的切片需要实现sort.Interface接口,在代码上不太简洁。Go 提供Slice/SliceStable函数只需传入一个待排序的切片,一个回调函数即可进行排序。需要注意,除了下列三个函数,sort 包下其它排序函数的实现原理都是通过sort.Interface接口,后文会进行分析。

    // 使用 less 函数定义的规则对切片 x 进行排序,不保证排序的稳定性,x 不是切片会报 panic
    func Slice(x interface{}, less func(i, j int) bool)
    
    // 使用 less 函数定义的规则对切片 x 进行排序,保证排序的稳定性,x 不是切片会报 panic
    func SliceStable(x interface{}, less func(i, j int) bool)
    
    // 判断切片 x 根据 less 函数定义的规则是否是有序的,x 不是切片会报 panic
    func SliceIsSorted(x interface{}, less func(i, j int) bool)
    
    // 在长度为 n 的升序序列中使用二分法查询满足 f(i) = true 的索引位置,判断条件必须为 >=
    func Search(n int, f func(int) bool) int
    

    ⭐️ 示例代码

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    type Student struct {
        Name string
        Age  int
    }
    
    func main() {
        ss := []Student{
            {"Alice", 18},
            {"Bob", 20},
            {"Allen", 16},
            {"Michelle", 18},
            {"James", 24},
        }
    
        less := func(i, j int) bool {
            return ss[i].Age < ss[j].Age
        }
        // 按照年龄递增排序
        sort.Slice(ss, less)
        fmt.Println(ss) // [{Allen 16} {Alice 18} {Michelle 18} {Bob 20} {James 24}]
        // 判断是否已经被排序
        fmt.Println(sort.SliceIsSorted(ss, less)) // true
    
        // 查找年龄等于 20 的学生的索引位置,判断条件必须为 >=
        f := func(i int) bool {
            return ss[i].Age >= 20
        }
        fmt.Println(sort.Search(len(ss), f)) // 3
    }
    

    基本数据类型排序

    对于 int、float64 和 string 类型的切片,Go 语言进行了封装,可以直接调用 sort 包中的函数进行排序。

    int 类型排序

    // 在 sort 包下,Go 语言定义了 IntSlice 类型实现 sort.Interface 接口,用于 []int 排序
    type IntSlice []int
    
    // 实现 Interface 接口
    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] }
    
    // 等价调用 sort.Sort(x)
    func (x IntSlice) Sort() { Sort(x) }
    
    // 等价调用 sort.SearchInts(x, p)
    func (x IntSlice) Search(p int) int { return SearchInts(x, p) }
    
    // 对 x 进行递增排序
    func Ints(x []int)
    
    // 判断 x 是否为递增序列
    func IntsAreSorted(x []int)
    
    // 在递增序列的 a 中搜索 x,返回 x 的索引
    // 如果查找不到,返回值是 x 应该插入 a 的位置(以保证 a 的递增顺序),返回值可以是 len(a)
    func SearchInts(a []int, x int) int
    

    ✏️ 示例代码

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    func main() {
        // 递增排序
        // 方式一:
        intList1 := []int{2, 0, 1, 8, 0, 9, 2, 4, 1, 2}
        sort.Ints(intList1)
        fmt.Println(intList1) // [0 0 1 1 2 2 2 4 8 9]
        // 方式二:
        intList2 := []int{2, 0, 1, 8, 0, 9, 2, 4, 1, 2}
        sort.Sort(sort.IntSlice(intList2))
        fmt.Println(intList2) // [0 0 1 1 2 2 2 4 8 9]
        // 方法三:
        intList3 := []int{2, 0, 1, 8, 0, 9, 2, 4, 1, 2}
        (sort.IntSlice(intList3)).Sort()
        fmt.Println(intList3) // [0 0 1 1 2 2 2 4 8 9]
        // 方式四
        intList4 := []int{2, 0, 1, 8, 0, 9, 2, 4, 1, 2}
        sort.Slice(intList4, func(i, j int) bool {
            return intList4[i] < intList4[j]
        })
        fmt.Println(intList4) // [0 0 1 1 2 2 2 4 8 9]
    
        // 判断是否为递增排序
        // 方式一:
        fmt.Println(sort.IntsAreSorted(intList1)) // true
        // 方式二:
        fmt.Println(sort.IsSorted(sort.IntSlice(intList2))) // true
    
        // 递减排序
        // 方式一:
        intList5 := []int{2, 0, 1, 8, 0, 9, 2, 4, 1, 2}
        sort.Sort(sort.Reverse(sort.IntSlice(intList5)))
        fmt.Println(intList5) // [9 8 4 2 2 2 1 1 0 0]
        // 方式二:
        intList6 := []int{2, 0, 1, 8, 0, 9, 2, 4, 1, 2}
        sort.Slice(intList6, func(i, j int) bool {
            return intList6[i] > intList6[j]
        })
        fmt.Println(intList6) // [9 8 4 2 2 2 1 1 0 0]
    
        // 在递增序列中搜索
        intList7 := []int{0, 0, 1, 1, 2, 2, 2, 4, 8, 9}
        // 方式一:
        fmt.Println(sort.SearchInts(intList7, 2)) // 4
        // 方式二:
        fmt.Println((sort.IntSlice(intList7)).Search(2)) // 4
    }
    

    float64 类型排序

    // 在 sort 包下,Go 语言定义了 Float64Slice 类型实现 sort.Interface 接口,用于 []float64 排序
    type Float64Slice []float64
    
    // 实现 Interface 接口
    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] }
    
    // 等价调用 sort.Sort(x)
    func (x Float64Slice) Sort() { Sort(x) }
    
    // 等价调用 sort.SearchFloat64s(x, p)
    func (x Float64Slice) Search(p float64) int { return SearchFloat64s(x, p) }
    
    // 对 x 进行递增排序
    func Float64s(x []float64)
    
    // 判断 x 是否为递增序列
    func Float64sAreSorted(x []float64)
    
    // 在递增序列的 a 中搜索 x,返回 x 的索引
    // 如果查找不到,返回值是 x 应该插入 a 的位置(以保证 a 的递增顺序),返回值可以是 len(a)
    func SearchFloat64s(a []float64, x float64) int
    

    示例代码

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    func main() {
        // 递增排序
        // 方式一:
        floatList1 := []float64{4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
        sort.Float64s(floatList1)
        fmt.Println(floatList1) // [3.14 4.2 5.9 10 12.3 27.81828 31.4 50.4 99.9]
        // 方式二:
        floatList2 := []float64{4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
        sort.Sort(sort.Float64Slice(floatList2))
        fmt.Println(floatList2) // [3.14 4.2 5.9 10 12.3 27.81828 31.4 50.4 99.9]
        // 方法三:
        floatList3 := []float64{4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
        (sort.Float64Slice(floatList3)).Sort()
        fmt.Println(floatList3) // [3.14 4.2 5.9 10 12.3 27.81828 31.4 50.4 99.9]
        // 方式四
        floatList4 := []float64{4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
        sort.Slice(floatList4, func(i, j int) bool {
            return floatList4[i] < floatList4[j]
        })
        fmt.Println(floatList4) // [3.14 4.2 5.9 10 12.3 27.81828 31.4 50.4 99.9]
    
        // 判断是否为递增排序
        // 方式一:
        fmt.Println(sort.Float64sAreSorted(floatList1)) // true
        // 方式二:
        fmt.Println(sort.IsSorted(sort.Float64Slice(floatList2))) // true
    
        // 递减排序
        // 方式一:
        floatList5 := []float64{4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
        sort.Sort(sort.Reverse(sort.Float64Slice(floatList5)))
        fmt.Println(floatList5) // [99.9 50.4 31.4 27.81828 12.3 10 5.9 4.2 3.14]
        // 方式二:
        floatList6 := []float64{4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
        sort.Slice(floatList6, func(i, j int) bool {
            return floatList6[i] > floatList6[j]
        })
        fmt.Println(floatList6) // [99.9 50.4 31.4 27.81828 12.3 10 5.9 4.2 3.14]
    
        // 在递增序列中搜索
        floatList7 := []float64{3.14, 4.2, 5.9, 10, 12.3, 27.81828, 31.4, 50.4, 99.9}
        // 方式一:
        fmt.Println(sort.SearchFloat64s(floatList7, 12.3)) // 4
        // 方式二:
        fmt.Println((sort.Float64Slice(floatList7)).Search(12.3)) // 4
    }
    

    string 类型排序

    // 在 sort 包下,Go 语言定义了 StringSlice 类型实现 sort.Interface 接口,用于 []string 排序
    type StringSlice []string
    
    // 实现 Interface 接口
    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] }
    
    // 等价调用 sort.Sort(x)
    func (x StringSlice) Sort() { Sort(x) } 
    
    // 等价调用 sort.SearchStrings(x, p)
    func (x StringSlice) Search(p string) int { return SearchStrings(x, p) }
    
    // 对 x 进行递增排序
    func Strings(x []string)
    
    // 判断 x 是否为递增序列
    func StringsAreSorted(x []string)
    
    // 在递增序列的 a 中搜索 x,返回 x 的索引
    // 如果查找不到,返回值是 x 应该插入 a 的位置(以保证 a 的递增顺序),返回值可以是 len(a)
    func SearchStrings(a []string, x string) int
    

    ✌ 示例代码

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    func main() {
        // 递增排序
        // 方式一:
        stringList1 := []string{"o", "l", "d", "b", "o", "y", "g", "o", "l", "a", "n", "g"}
        sort.Strings(stringList1)
        fmt.Printf("%q\n", stringList1) // ["a" "b" "d" "g" "g" "l" "l" "n" "o" "o" "o" "y"]
        // 方式二:
        stringList2 := []string{"o", "l", "d", "b", "o", "y", "g", "o", "l", "a", "n", "g"}
        sort.Sort(sort.StringSlice(stringList2))
        fmt.Printf("%q\n", stringList2) // ["a" "b" "d" "g" "g" "l" "l" "n" "o" "o" "o" "y"]
        // 方式三:
        stringList3 := []string{"o", "l", "d", "b", "o", "y", "g", "o", "l", "a", "n", "g"}
        (sort.StringSlice(stringList3)).Sort()
        fmt.Printf("%q\n", stringList3) // ["a" "b" "d" "g" "g" "l" "l" "n" "o" "o" "o" "y"]
        // 方式四
        stringList4 := []string{"o", "l", "d", "b", "o", "y", "g", "o", "l", "a", "n", "g"}
        sort.Slice(stringList4, func(i, j int) bool {
            return stringList4[i] < stringList4[j]
        })
        fmt.Printf("%q\n", stringList4) // ["a" "b" "d" "g" "g" "l" "l" "n" "o" "o" "o" "y"]
    
        // 判断是否为递增排序
        // 方式一:
        fmt.Println(sort.StringsAreSorted(stringList1)) // true
        // 方式二:
        fmt.Println(sort.IsSorted(sort.StringSlice(stringList2))) // true
    
        // 递减排序
        // 方式一:
        stringList5 := []string{"o", "l", "d", "b", "o", "y", "g", "o", "l", "a", "n", "g"}
        sort.Sort(sort.Reverse(sort.StringSlice(stringList5)))
        fmt.Printf("%q\n", stringList5) // ["y" "o" "o" "o" "n" "l" "l" "g" "g" "d" "b" "a"]
        // 方式二:
        stringList6 := []string{"o", "l", "d", "b", "o", "y", "g", "o", "l", "a", "n", "g"}
        sort.Slice(stringList6, func(i, j int) bool {
            return stringList6[i] > stringList6[j]
        })
        fmt.Printf("%q\n", stringList6) // ["y" "o" "o" "o" "n" "l" "l" "g" "g" "d" "b" "a"]
    
        // 在递增序列中搜索
        stringList7 := []string{"a", "b", "d", "g", "g", "l", "l", "n", "o", "o", "o", "y"}
        // 方式一:
        fmt.Println(sort.SearchStrings(stringList7, "l")) // 5
        // 方式二:
        fmt.Println((sort.StringSlice(stringList7)).Search("l")) // 5
    }
    

    底层实现分析

    sort.Sort 函数

    // Sort 函数是一个不稳定方式排序,使用希尔快速、快速排序或者堆排序三种排序方式之一
    func Sort(data Interface) {
        n := data.Len()
        // maxDepth(n) 返回 2*ceil(lg(n+1)),元素深度达到 2*ceil(lg(n+1)) 则选用堆排序
        quickSort(data, 0, n, maxDepth(n))
    }
    
    // quickSort 会根据与元素深度自动选择使用希尔快速、快速排序或者堆排序三种排序方式之一
    func quickSort(data Interface, a, b, maxDepth int) {
        for b-a > 12 {
            if maxDepth == 0 { // Use ShellSort for slices <= 12 elements
                // 使用堆排序
                heapSort(data, a, b)
                return
            }
            maxDepth--
            // 使用三向切分快速排序,通过 doPivot 进行快排的分区
            mlo, mhi := doPivot(data, a, b)
            // Avoiding recursion on the larger subproblem guarantees
            // a stack depth of at most lg(b-a).
            if mlo-a < b-mhi {
                quickSort(data, a, mlo, maxDepth)
                a = mhi // i.e., quickSort(data, mhi, b)
            } else {
                quickSort(data, mhi, b, maxDepth)
                b = mlo // i.e., quickSort(data, a, mlo)
            }
        }
        // 切片元素小于等于 12 个,使用希尔排序(希尔排序是插入排序的高效版本),间隔 d=6
        if b-a > 1 {
            // Do ShellSort pass with gap 6
            // It could be written in this simplified form cause b-a <= 12
            for i := a + 6; i < b; i++ {
                if data.Less(i, i-6) {
                    data.Swap(i, i-6)
                }
            }
            insertionSort(data, a, b)
        }
    }
    
    // 堆排序
    func heapSort(data Interface, a, b int) {
        first := a
        lo := 0
        hi := b - a
    
        // Build heap with greatest element at top.
        for i := (hi - 1) / 2; i >= 0; i-- {
            siftDown(data, i, hi, first)
        }
    
        // Pop elements, largest first, into end of data.
        for i := hi - 1; i >= 0; i-- {
            data.Swap(first, first+i)
            siftDown(data, lo, i, first)
        }
    }
    
    // siftDown implements the heap property on data[lo:hi].
    // first is an offset into the array where the root of the heap lies.
    func siftDown(data Interface, lo, hi, first int) {
        root := lo
        for {
            child := 2*root + 1
            if child >= hi {
                break
            }
            if child+1 < hi && data.Less(first+child, first+child+1) {
                child++
            }
            if !data.Less(first+root, first+child) {
                return
            }
            data.Swap(first+root, first+child)
            root = child
        }
    }
    
    // 插入排序
    // insertionSort sorts data[a:b] using insertion sort.
    func insertionSort(data Interface, a, b int) {
        for i := a + 1; i < b; i++ {
            for j := i; j > a && data.Less(j, j-1); j-- {
                data.Swap(j, j-1)
            }
        }
    }
    

    sort.Stable 函数

    // Stable 是一个稳定方式的排序,使用归并排序
    func Stable(data Interface) {
        stable(data, data.Len())
    }
    
    // 这里用到的归并排序算法是一种原址排序算法:
    // 首先,它把 slice 按照每 blockSize=20 个元素为一个 slice,进行插入排序
    // 循环合并相邻的两个 block,每次循环 blockSize 扩大二倍,直到 blockSize > n 为止
    func stable(data Interface, n int) {
        // 初始 blockSize 设置为 20
        blockSize := 20 // must be > 0
        a, b := 0, blockSize
        // 对每个块(以及剩余不足blockSize的一个块)进行插入排序
        for b <= n {
            insertionSort(data, a, b)
            a = b
            b += blockSize
        }
        insertionSort(data, a, n)
        
        for blockSize < n {
            a, b = 0, 2*blockSize
            for b <= n {
                // 每两个 blockSize 进行合并
                symMerge(data, a, a+blockSize, b)
                a = b
                b += 2 * blockSize
            }
            // 剩余一个多 blockSize 进行合并
            if m := a + blockSize; m < n {
                symMerge(data, a, m, n)
            }
            blockSize *= 2
        }
    }
    
    func symMerge(data Interface, a, m, b int) {
        // Avoid unnecessary recursions of symMerge
        // by direct insertion of data[a] into data[m:b]
        // if data[a:m] only contains one element.
        if m-a == 1 {
            // Use binary search to find the lowest index i
            // such that data[i] >= data[a] for m <= i < b.
            // Exit the search loop with i == b in case no such index exists.
            i := m
            j := b
            for i < j {
                h := int(uint(i+j) >> 1)
                if data.Less(h, a) {
                    i = h + 1
                } else {
                    j = h
                }
            }
            // Swap values until data[a] reaches the position before i.
            for k := a; k < i-1; k++ {
                data.Swap(k, k+1)
            }
            return
        }
    
        // Avoid unnecessary recursions of symMerge
        // by direct insertion of data[m] into data[a:m]
        // if data[m:b] only contains one element.
        if b-m == 1 {
            // Use binary search to find the lowest index i
            // such that data[i] > data[m] for a <= i < m.
            // Exit the search loop with i == m in case no such index exists.
            i := a
            j := m
            for i < j {
                h := int(uint(i+j) >> 1)
                if !data.Less(m, h) {
                    i = h + 1
                } else {
                    j = h
                }
            }
            // Swap values until data[m] reaches the position i.
            for k := m; k > i; k-- {
                data.Swap(k, k-1)
            }
            return
        }
    
        mid := int(uint(a+b) >> 1)
        n := mid + m
        var start, r int
        if m > mid {
            start = n - b
            r = mid
        } else {
            start = a
            r = m
        }
        p := n - 1
    
        for start < r {
            c := int(uint(start+r) >> 1)
            if !data.Less(p-c, c) {
                start = c + 1
            } else {
                r = c
            }
        }
    
        end := n - start
        if start < m && m < end {
            rotate(data, start, m, end)
        }
        if a < start && start < mid {
            symMerge(data, a, start, mid)
        }
        if mid < end && end < b {
            symMerge(data, mid, end, b)
        }
    }
    

    sort.Slice 函数

    // Slice 函数是一个不稳定方式排序,使用希尔快速、快速排序或者堆排序三种排序方式之一
    // Slice sorts the slice x given the provided less function.
    // It panics if x is not a slice.
    //
    // The sort is not guaranteed to be stable: equal elements
    // may be reversed from their original order.
    // For a stable sort, use SliceStable.
    //
    // The less function must satisfy the same requirements as
    // the Interface type's Less method.
    func Slice(x interface{}, less func(i, j int) bool) {
        rv := reflectValueOf(x)
        swap := reflectSwapper(x)
        length := rv.Len()
        // maxDepth(n) 返回 2*ceil(lg(n+1)),元素深度达到 2*ceil(lg(n+1)) 则选用堆排序
        quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
    }
    
    // lessSwap is a pair of Less and Swap function for use with the
    // auto-generated func-optimized variant of sort.go in
    // zfuncversion.go.
    type lessSwap struct {
        Less func(i, j int) bool
        Swap func(i, j int)
    }
    
    // quickSort_func 会根据与元素深度自动选择使用希尔快速、快速排序或者堆排序三种排序方式之一
    // Auto-generated variant of sort.go:quickSort
    func quickSort_func(data lessSwap, a, b, maxDepth int) {
        for b-a > 12 {
            if maxDepth == 0 {
                // 使用堆排序
                heapSort_func(data, a, b)
                return
            }
            maxDepth--
            // 使用三向切分快速排序,通过 doPivot_func 进行快排的分区
            mlo, mhi := doPivot_func(data, a, b)
            if mlo-a < b-mhi {
                quickSort_func(data, a, mlo, maxDepth)
                a = mhi
            } else {
                quickSort_func(data, mhi, b, maxDepth)
                b = mlo
            }
        }
        // 切片元素小于等于 12 个,使用希尔排序(希尔排序是插入排序的高效版本),间隔 d=6
        if b-a > 1 {
            for i := a + 6; i < b; i++ {
                if data.Less(i, i-6) {
                    data.Swap(i, i-6)
                }
            }
            insertionSort_func(data, a, b)
        }
    }
    

    从上面可以看到,sort.Slice调用的排序函数quickSort_func的入参类型是data lessSwap,而不是data Interface,调用的插入排序、堆排序、快速排序函数也和sort.Sort不同。sort.Slicesort.Sort的实现原理是相同的,区别在于sort.Sort通过传入实现sort.Interface接口的对象获得Len()/Swap()/Less(),而sort.Slice是通过反射的方式获取Len()Swap()Less()通过传参获得。因此,sort.Slice传入切片和Less()函数即可实现排序。


    sort.SliceStable 函数

    // SliceStable 是一个稳定方式的排序,使用归并排序
    // SliceStable sorts the slice x using the provided less
    // function, keeping equal elements in their original order.
    // It panics if x is not a slice.
    //
    // The less function must satisfy the same requirements as
    // the Interface type's Less method.
    func SliceStable(x interface{}, less func(i, j int) bool) {
        rv := reflectValueOf(x)
        swap := reflectSwapper(x)
        stable_func(lessSwap{less, swap}, rv.Len())
    }
    
    // lessSwap is a pair of Less and Swap function for use with the
    // auto-generated func-optimized variant of sort.go in
    // zfuncversion.go.
    type lessSwap struct {
        Less func(i, j int) bool
        Swap func(i, j int)
    }
    
    // 这里用到的归并排序算法是一种原址排序算法:
    // 首先,它把 slice 按照每 blockSize=20 个元素为一个 slice,进行插入排序
    // 循环合并相邻的两个 block,每次循环 blockSize 扩大二倍,直到 blockSize > n 为止
    // Auto-generated variant of sort.go:stable
    func stable_func(data lessSwap, n int) {
        blockSize := 20  // 初始 blockSize 设置为 20
        a, b := 0, blockSize
        // 对每个块(以及剩余不足blockSize的一个块)进行插入排序
        for b <= n {
            insertionSort_func(data, a, b)
            a = b
            b += blockSize
        }
        insertionSort_func(data, a, n)
        for blockSize < n {
            a, b = 0, 2*blockSize
            for b <= n {
                // 每两个 blockSize 进行合并
                symMerge_func(data, a, a+blockSize, b)
                a = b
                b += 2 * blockSize
            }
            // 剩余一个多 blockSize 进行合并
            if m := a + blockSize; m < n {
                symMerge_func(data, a, m, n)
            }
            blockSize *= 2
        }
    }
    

    sort.Slice一样,sort.SliceStable调用的排序函数stable_func的入参类型是data lessSwap,不是data Interface,通过反射的方式获取Len()Swap()Less()通过传参获得。


    参考

    1. 常见排序算法总结和 Go 标准库排序源码分析
    2. go语言中sort包的实现方法与应用详解
  • 相关阅读:
    Android开源框架——Volley
    Android中的事件传递机制
    @ViewDebug.ExportedProperty的使用
    字符间距——扩展
    读取assets文件夹下图片(ods_interview)
    Android消息推送——JPush极光推送
    深入模块
    正则表达式和re模块
    初识模块
    迭代器和生成器
  • 原文地址:https://www.cnblogs.com/zongmin/p/15632106.html
Copyright © 2020-2023  润新知