• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Go 语言标准库之 sort 包

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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

实现了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包的实现方法与应用详解

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
go语言的格式化打印发布时间:2022-07-10
下一篇:
[Go] 让 go build 生成的可执行文件对 Mac、linux、Windows 平台一致发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap