Golang---sort包
Sort 包介绍
Go 语言标准库 sort 包中实现了几种基本的排序算法:插入排序、快速排序和堆排序,但是在使用 sort 包进行排序时无需具体考虑使用哪种排序方式,因为该方法会根据传入的排序的数据量来进行自动选择合适的排序算法。
func insertionSort(data Interface, a, b int) // 插入排序
func heapSort(data Interface, a, b int) // 堆排序
func quickSort(data Interface, a, b, maxDepth int) // 快速排序
sort.Interface 接口定义了以下三个方法,只要实现了这三个方法,就可以对数据集合进行排序,sort 包会根据实际数据自动选择高效的排序算法。
// sort.go
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)
}
Sort 包自带的排序实现
在 Go 的 sort 包中,给我们实现了三种类型的排序,分别是 Int, string, float64 类型,我们来具体看一下 Int 类型的实现:
// sort.go
// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
type IntSlice []int func (p IntSlice) Len() int { return len(p) }
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // Sort is a convenience method.
func (p IntSlice) Sort() { Sort(p) }
可以看到 Go 已经给 int 数组实现了这三种方法,其它两种类型基本相同,所以我们在对上述三种类型的数据进行排序的时候,可以不必自己实现上述接口,直接调用得到排序结果。
Sort 包自定义排序方式
通过以上描述,我们知道只有上述三种类型是 Go 帮我们实现好的,那如果我们要对结构体进行排序,该如何实现呢?同理,我们只需要给自己定义的待排序的结构体类型实现上述接口就可以了。我们来看一下具体示例:
func main() {
a := personSlice{
{
Name: "AAA",
Age: ,
},
{
Name: "BBB",
Age: ,
},
{
Name: "CCC",
Age: ,
},
{
Name: "DDD",
Age: ,
},
{
Name: "EEE",
Age: ,
},
}
sort.Sort(a)
fmt.Println("Sort: ", a)
sort.Stable(a) // 稳定排序
fmt.Println("Stable: ", a)
}
自定义排序示例
Sort 包如何选择最合适的排序方式
我们上面说用 sort 进行排序不用关心采用哪种排序方式,但是 sort 又是根据什么来选择排序方式的呢?在 sort 包自带的排序实现一节中,我们看到,上面的类型都是通过 sort.Sort() ,进一步调用 Sort(p) 来进行排序的,那我们来看一下 Sort(p) 所采用的排序策略:
// sort.go
// 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, , n, maxDepth(n))
}
可以看到 Sort 函数的参数为接口类型,这说明可以传入任何类型的参数 ;然后调用 quickSort 函数进行排序,其中参数 maxDepth(n) 为什么呢?我们看一下:
// sort.go
// maxDepth returns a threshold at which quicksort should switch
// to heapsort. It returns 2*ceil(lg(n+1)).
func maxDepth(n int) int {
var depth int
for i := n; i > ; i >>= {
depth++
}
return depth *
}
注释告诉我们,这个函数返回一个阈值,用来区分是用快排还是用堆排序。那我们回去看一下 quickSort 是怎么根据这个阈值进行区分的:
// sort.go
func quickSort(data Interface, a, b, maxDepth int) {
for b-a > { // Use ShellSort for slices <= 12 elements
if maxDepth == {
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 > {
// Do ShellSort pass with gap 6
// It could be written in this simplified form cause b-a <= 12
for i := a + ; i < b; i++ {
if data.Less(i, i-) {
data.Swap(i, i-)
}
}
insertionSort(data, a, b)
}
}
从上面的代码逻辑中可以看到,当元素个数(b-a) 大于 12 时,采用快排(算法中选取选取枢纽值进行了优化),当 maxDepth == 0 时采用堆排序(此处不是很理解);
当 元素个数(b-a) 大于 1 并且小于等于 12 时,首先进行一轮 step == 6 的希尔排序,然后进行插入排序。
Sort 包常用方法
func main() {
a := []int{1, 3, 5, 7, 2}
b := sort.IntSlice{2, 4, 6, 8}
fmt.Println(b)
//=====int=====
c := sort.IntSlice{2, 1, 4, 3, 7}
fmt.Println(c)
sort.Ints(c)
sort.IntsAreSorted(c)
sort.IsSorted(c)
sort.SearchInts(a, 5)
//=====string====
d := sort.StringSlice{"aaa", "bbb", "ccc"}
fmt.Println(d)
sort.Strings(d)
sort.StringsAreSorted(d)
sort.IsSorted(d)
sort.SearchStrings(d, "bbb")
//=====Float64=====
e := sort.Float64Slice{2.1, 2.6, 7.8, 0.5}
fmt.Println(e)
sort.Float64s(e)
sort.Float64sAreSorted(e)
sort.IsSorted(e)
sort.SearchFloat64s(e, 7.8)
//====common function===
/* search(n, func) 使用二分法进行查找指定切片[0:n],返回能使 f(i)=true 的最小的 i(0<=i<n) 的值
并且会假定,如果 f(i)=true, 则 f(i+1)=true
当在切片中无法找到 f(i)=true 的 i 时, 该方法返回 n,而不是返回 -1
notice: 上述的三种 search 查找方法中,其对应的 slice 必须按照升序进行排序,否则会出现奇怪的结果
*/
f := []int{1, 2, 3}
ff := sort.Search(len(f), func(i int) bool {
return f[i] == 8
}) // ff=len(f)==3
fmt.Println(ff)
/* Sort(data Interface) 会对 data 进行排序,为不稳定排序,可以根据不同形式决定
使用不同的排序方式(插入排序,堆排序,快排)
*/
/* Reverse(data Interface) Interface 实现对 data 的逆序排列,结果返回一个 Interface
需要再次调用 sort.Sort(data Interface) 对逆序的结果进行输出
*/
g := sort.IntSlice{3, 2, 4}
sort.Sort(sort.Reverse(g))
fmt.Println(g) // 4, 3, 2
}
Golang---sort包的更多相关文章
- golang sort包使用
https://studygolang.com/static/pkgdoc/pkg/sort.htm#StringSlice.Search package main import ( "fm ...
- golang sort包 排序
[]float64: ls := sort.Float64Slice{ 1.1, 4.4, 5.5, 3.3, 2.2, } fmt.Println(ls) //[1.1 4.4 5.5 3.3 2. ...
- Golang学习 - sort 包
------------------------------------------------------------ // 满足 Interface 接口的类型可以被本包的函数进行排序. type ...
- Golang fmt包使用小技巧
h1 { margin-top: 0.6cm; margin-bottom: 0.58cm; direction: ltr; color: #000000; line-height: 200%; te ...
- Golang Vendor 包机制 及 注意事项
现在的 Go 版本是 1.8,早在 1.5 时期,就有了 Vendor 包机制,详情可查看博文:“理解 Go 1.5 vendor”. 遇到的问题 个人在使用 Glide 管理 Vendor 包时(附 ...
- Golang Vendor 包管理工具 glide 使用教程
Glide 是 Golang 的 Vendor 包管理器,方便你管理 vendor 和 verdor 包.类似 Java 的 Maven,PHP 的 Composer. Github:https:// ...
- golang reflect包使用解析
golang reflect包使用解析 参考 Go反射编码 2个重要的类型 Type Value 其中Type是interface类型,Value是struct类型,意识到这一点很重要 Type和Va ...
- Golang测试包
Golang测试包 golang自带了测试包(testing),直接可以进行单元测试.性能分析.输出结果验证等.简单看着官方文档试了试,总结一下: 目录结构和命令 使用golang的测试包,需要遵循简 ...
- Golang : cobra 包解析
笔者在<Golang : cobra 包简介>一文中简要的介绍了 cobra 包及其基本的用法,本文我们从代码的角度来了解下 cobra 的核心逻辑. Command 结构体 Comman ...
- Golang : pflag 包简介
笔者在前文中介绍了 Golang 标准库中 flag 包的用法,事实上有一个第三方的命令行参数解析包 pflag 比 flag 包使用的更为广泛.pflag 包的设计目的就是替代标准库中的 flag ...
随机推荐
- 区块链 - 哈希(Hash)
章节 区块链 – 介绍 区块链 – 发展历史 区块链 – 比特币 区块链 – 应用发展阶段 区块链 – 非对称加密 区块链 – 哈希(Hash) 区块链 – 挖矿 区块链 – 链接区块 区块链 – 工 ...
- PAT (Advanced Level) 1128~1131:1128N皇后 1129 模拟推荐系统(set<Node>优化) 1130 中缀表达式
1128 N Queens Puzzle(20 分) 题意:N皇后问题.按列依次给定N个皇后的行号,问N个皇后是否能同时不存在行冲突.列冲突和主副对角线冲突. 分析: 1.根据题意一定不存在列冲突,所 ...
- 关于目标检测的anchor问题
关于目标检测其实我一直也在想下面的两个论断: Receptive Field Is Natural Anchor Receptive Field Is All You Need 只是一直没有实验.但是 ...
- 第3节 sqoop:2、sqoop的基本简介和安装
3. sqoop数据迁移 3.1.概述 sqoop是apache旗下一款“Hadoop和关系数据库服务器之间传送数据”的工具. 导入数据:MySQL,Oracle导入数据到Hadoop的HDFS.HI ...
- 安卓:从assets目录下复制文件到指定目录
有些时候我们直接将某些资源文件内置到apk中,便于直接使用. 1.首先将文件放置在项目/app/src/main/assets目录中 2.功能代码: public void copyFile(Stri ...
- Hibernate(十)--spring整合hibernate
结构: Spring和Hibernate整合借助于HibernateTemplate applicationContext.xml <?xml version="1.0" e ...
- kali linux终端快捷键设置
kali里面是没有终端快捷键的,需要自己设置. 打开设置->设备->keyboard,拉到最下面点击加号来新建一个快捷键. 名称:打开终端 命令:gnome-terminal 快捷键:Ct ...
- MyBatis 逆向工程(MyBatis 自动生成接口以及xml)的使用
刚学MyBatis逆向工程(还以为要反汇编呢.....) MyBatis逆向工程 个人理解就是链接数据库自动生成相关的增删改查相关的类 以及xml文件 (其中有一些不足 应该就是多表链接的问题需要自己 ...
- node - 获取当前时间并格式化
1,安装 moment模块 cnpm i moment --save 2,引入 var moment = require('moment'); 3,获取当前时间并格式化 var current_tim ...
- 《Python爬虫技术:深入理解原理、技术与开发》已经出版,送Python基础视频课程
好消息,<Python爬虫技术:深入理解原理.技术与开发>已经出版!!! JetBrains官方推荐图书!JetBrains官大中华区市场部经理赵磊作序!送Python基础视频课程!J ...