目录
不稳定排序
稳定排序
不稳定
稳定
判断是否有序
查找元素
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源码中:
可以发现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
}