目录

​基础数据类型排序​

​不稳定排序​

​稳定排序​

​结构体类型排序​

​不稳定​

​稳定​

​判断是否有序​

​查找元素​



go语言中文文档:​​Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国​

sort用于各种排序,这里仅列出sort中一些常用的函数方法:

基础数据类型排序

可以对整数、浮点数、字符串进行正序和逆序排序。

不稳定排序

sort.Sort()函数不能保证排序的稳定性

分析:

Sort()源码:

// Sort sorts data.
// It makes one call to data.Len to determine n and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
n := data.Len()
quickSort(data, 0, n, maxDepth(n))
}

从Sort()源码可以看出其底层使用的是快排:

func quickSort(data Interface, a, b, maxDepth int) {
for b-a > 12 { // Use ShellSort for slices <= 12 elements
if maxDepth == 0 {
heapSort(data, a, b)
return
}
maxDepth--
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)
}
}
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)
}
}

快排是不稳定的。

因为在sort源码中:

Go语言sort库函数的使用_数据结构

可以发现Ints、Float64s、Strings底层使用的是Sort(),所以他们三个也是不稳定的。

package main

import (
"fmt"
"sort"
)

func main() {
//整数排序
a := []int{1,3,5,2,35}
// 正序
sort.Ints(a)
fmt.Println("正序sort.Ints():a=",a)
sort.Sort(sort.IntSlice(a))
fmt.Println("正序sort.Sort():a=",a)
// 逆序
sort.Sort(sort.Reverse(sort.IntSlice(a)))
fmt.Println("逆序:a=",a)


//浮点数排序
b := []float64{1.2,5.6,3.4,7.0,2.5}
// 正序
sort.Float64s(b)
fmt.Println("正序sort.Float64s():b=",b)
sort.Sort(sort.Float64Slice(b))
fmt.Println("正序sort.Sort():b=",b)
// 逆序
sort.Sort(sort.Reverse(sort.Float64Slice(b)))
fmt.Println("逆序:b=",b)


//字符串排序
c := []string{"aaa","dds","ccc","bbd"}
// 正序
sort.Strings(c)
fmt.Println("正序sort.Strings():c=",c)
sort.Sort(sort.StringSlice(c))
fmt.Println("正序sort.Sort():c=",c)
// 逆序
sort.Sort(sort.Reverse(sort.StringSlice(c)))
fmt.Println("逆序:c=",c)

}

稳定排序

sort.Stable()函数能保证排序的稳定性

分析:

Stable()源码:

// Stable sorts data while keeping the original order of equal elements.
//
// It makes one call to data.Len to determine n, O(n*log(n)) calls to
// data.Less and O(n*log(n)*log(n)) calls to data.Swap.
func Stable(data Interface) {
stable(data, data.Len())
}


func stable(data Interface, n int) {
blockSize := 20 // must be > 0
a, b := 0, 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 {
symMerge(data, a, a+blockSize, b)
a = b
b += 2 * blockSize
}
if m := a + blockSize; m < n {
symMerge(data, a, m, n)
}
blockSize *= 2
}
}

从stable()源码可以看出其底层使用的是insertionSort()插入排序,准确的说是直接插入排序:

// 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)
}
}
}

直接插入排序是稳定的。

package main

import (
"fmt"
"sort"
)

func main() {
//整数排序
a := []int{1,3,5,2,35}
// 正序
sort.Stable(sort.IntSlice(a))
fmt.Println("正序sort.Stable():a=",a)

//浮点数排序
b := []float64{1.2,5.6,3.4,7.0,2.5}
sort.Stable(sort.Float64Slice(b))
fmt.Println("正序sort.Stable():b=",b)

//字符串排序
c := []string{"aaa","dds","ccc","bbd"}
// 正序
sort.Stable(sort.StringSlice(c))
fmt.Println("正序sort.Stable():c=",c)
}

结构体类型排序

可以设置按照结构体各个值的排序顺序。

不稳定

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()
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
}

从中可以看出其底层使用的是快排:

// 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--
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
}
}
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)
}
}

快排是不稳定的

package main

import (
"fmt"
"sort"
)

//定义一个结构体
type Student struct {
Score int
Name string
}


func main() {
x := []Student{ {2, "lcc"},{1, "ry"},{2, "yyr"}, {3, "lyh"}}
sort.Slice(x, func(i, j int) bool {
if x[i].Score != x[j].Score {
return x[i].Score < x[j].Score
} else {
return x[i].Name < x[j].Name
}
})
fmt.Println(x)

}

稳定

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())
}

从中可以看出其底层使用的是插入排序:

// Auto-generated variant of sort.go:stable
func stable_func(data lessSwap, n int) {
blockSize := 20
a, b := 0, 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 {
symMerge_func(data, a, a+blockSize, b)
a = b
b += 2 * blockSize
}
if m := a + blockSize; m < n {
symMerge_func(data, a, m, n)
}
blockSize *= 2
}
}


package main

import (
"fmt"
"sort"
)

//定义一个结构体
type Student struct {
Score int
Name string
}


func main() {
x := []Student{ {2, "lcc"},{1, "ry"},{2, "yyr"}, {3, "lyh"}}
sort.SliceStable(x, func(i, j int) bool {
if x[i].Score != x[j].Score {
return x[i].Score < x[j].Score
} else {
return x[i].Name < x[j].Name
}
})
fmt.Println(x)
}

判断是否有序

sort.IsSorted()只能判断正序,尽管元素已经为逆序,也要经过sort.Reverse()处理一下,否则返回false。

package main

import (
"fmt"
"sort"
)

func main() {
//判断是否有序
fmt.Println(sort.IsSorted(sort.IntSlice([]int{5,4,3,2}))) // fasle
fmt.Println(sort.IsSorted(sort.Reverse(sort.IntSlice([]int{5,4,3,2})))) //true
fmt.Println(sort.IsSorted(sort.IntSlice([]int{1,2,4,5}))) //true
}

查找元素

Search函数采用二分法搜索找到[0, n)区间内最小的满足f(i)==true的值i,如果没有该值,函数会返回n。常用的就是找元素插入位置:找到值x在插入一个有序的、可索引的数据结构时,应插入的位置。

SearchInts、SearchFloat64s、SearchStrings都是将Search封装了一层

源码:

func Search(n int, f func(int) bool) int {
// Define f(-1) == false and f(n) == true.
// Invariant: f(i-1) == false, f(j) == true.
i, j := 0, n
for i < j {
h := int(uint(i+j) >> 1) // avoid overflow when computing h
// i ≤ h < j
if !f(h) {
i = h + 1 // preserves f(i-1) == false
} else {
j = h // preserves f(j) == true
}
}
// i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
return i
}

明显是用的二分查找嘛!!!使用二分查找,会从[0, n)中取出一个值index,index为[0, n)中最小的使函数f(index)为True的值,并且f(index+1)也为True。
如果无法找到该index值,则该方法为返回n。



package main

import (
"fmt"
"sort"
)

定义一个结构体
type Student struct {
Score int
Name string
}

func main() {
// 整数查找
a := []int{1, 2, 3, 5, 35}
fmt.Println(sort.SearchInts(a, 4)) //3
// 浮点数查找
b := []float64{1.2, 2.5, 3.4, 5.6, 7.0}
fmt.Println(sort.SearchFloat64s(b, 3.0)) //2
// 字符串查找
c := []string{"aaa", "bbd", "ccc", "dds"}
fmt.Println(sort.SearchStrings(c, "cac")) //2

// 自定义查找——查找学生中score为2且名字为lca学生的插入位置
x := []Student{{1, "ry"}, {2, "lcc"}, {2, "yyr"}, {3, "lyh"}}
fmt.Println(sort.Search(len(x), func(i int) bool {
return x[i].Score == 2 && x[i].Name >= "lca"
})) //1
}



Go语言sort库函数的使用_算法_02