go-sort排序
1. Overview
Package sort provides primitives for sorting slices and user-defined collections.
切片排序,或者是自定义集合的排序。
例子的话我觉得还是尽量看官方的,认准pkg.go.dev ,其他家博客的话例子举得不是很恰当。
我的话基本就是抄官方,加入一些自己的理解。
2. 实现
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s: %d", p.Name, p.Age)
}
// ByAge implements sort.Interface for []Person based on
// the Age field.
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func main() {
people := []Person{
{"Bob", 31},
{"John", 42},
{"Michael", 17},
{"Jenny", 26},
}
fmt.Println(people)
// There are two ways to sort a slice. First, one can define
// a set of methods for the slice type, as with ByAge, and
// call sort.Sort. In this first example we use that technique.
sort.Sort(ByAge(people))
fmt.Println(people)
// The other way is to use sort.Slice with a custom Less
// function, which can be provided as a closure. In this
// case no methods are needed. (And if they exist, they
// are ignored.) Here we re-sort in reverse order: compare
// the closure with ByAge.Less.
sort.Slice(people, func(i, j int) bool {
return people[i].Age > people[j].Age
})
fmt.Println(people)
}
主要是利用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))
}
主要是接收一个data interface的,然后调用quickSort(这里的quickSort并不是纯的quicksort ,高度优化过的quicksort,跟自己实现那种还是要复杂上好几倍,就不展开了)
// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should 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)
}
要现实三个函数,分别是Len(),Less(i,j) bool, Swap(i,j int),
完了之后调用就把切片,转换成排序的数据,强制转换一下,然后放入sort.Sort中即可。
sort.Sort(ByAge(people))
当然你可以定义ByOther。
这个例子后面还举了一个sort.Slice 直接跟一个匿名函数的用法
// The other way is to use sort.Slice with a custom Less
// function, which can be provided as a closure. In this
// case no methods are needed. (And if they exist, they
// are ignored.) Here we re-sort in reverse order: compare
// the closure with ByAge.Less.
sort.Slice(people, func(i, j int) bool {
return people[i].Age > people[j].Age
})
我觉得这种更接近java中的Arrays.sort(xxx,xxx),也不用写Swap和Len函数了,更实用一些,个人感觉。
3. 基础类型
比如int ,float64,String 这种有现成的函数就不用自己写了。
sort.Ints()
sort.Float64s()
sort.Strings()
4. 小结
主要是实现3个函数,Len,Swap ,Less ,前面两个没什么说的,主要逻辑在Less 里面定义。就好了。
再付一个例子, https://www.luogu.com.cn/problem/P1093
典型的结构体排序。
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
type Result struct {
Chinese int
Math int
Eng int
Id int
Sum int
}
type Results []Result
func (r Results) Len() int{
return len(r)
}
func (r Results)Swap(i,j int) {
r[i],r[j]=r[j],r[i]
}
func (r Results)Less(i,j int) bool {
if r[i].Sum != r[j].Sum{
return r[i].Sum > r[j].Sum
}
if r[i].Chinese != r[j].Chinese{
return r[i].Chinese > r[j].Chinese
}
return r[i].Id < r[j].Id
}
func main() {
var n int
fmt.Scanf("%d",&n)
res := make(Results,n)
for i := 0; i < n; i++ {
var a,b, c int
fmt.Scanf("%d %d %d",&a,&b,&c)
res[i]=Result{
Chinese: a,
Eng: c,
Math: b,
Id: i+1,
Sum: a+b+c,
}
}
sort.Sort(res)
for i :=0;i<5;i++{
fmt.Printf("%d %d\n",res[i].Id,res[i].Sum)
}
}
但是洛谷的oj对golang的输入输出会有一些问题,acwing就可以ac。 不用纠结。洛谷还是用c++比较好一点。