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 ...
随机推荐
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 图片:图片响应式 (将很好地扩展到父元素)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- HDU1880 魔咒词典
题目大意:对应的输入多行,每行两个字符串,两个字符串互相映射.接下来询问的时候,如果这个字符串出现过,输出其对应的字符串. 分析:二重哈希来判断字符串是否存在,输出其对应的字符串就行.二重哈希的入门题 ...
- 我的博客 Hexo 还是Jekyll
我的博客 Hexo 还是Jekyll 标签(空格分隔): 博客 很喜欢找一些博客主题,目前发现几个比较不错的 Hexo: 阿里中间件 我的个人博客-Material主题 我的个人博客-Fluid主题 ...
- java核心-多线程(9)- ThreadLocal类
1.背景 ThreadLocal类我想一般的码农或初级程序员在平时开发中基本上接触不到,但是面试老师会问.往高级点走会遇到这个类.这个类不是为了解决资源的竞争问题,而是为每个线程提供同一个容器 ...
- 007-PHP变量和函数相互转换
<?php function write($text) //定义function write()函数 { print($text); //打印字符串 } function writeBold($ ...
- 使用 HTML5 视频事件
转自:http://msdn.microsoft.com/zh-cn/library/hh924822(v=vs.85).aspx 为什么要使用事件? HTML5 视频对象提供了很多事件,这些事件可以 ...
- Xilinx Vivado器件分配管脚:LVDS差分电平信号如何分配管脚?
最近在把Quartus Prime 15.1的工程移植到Vivado 2019.1,需要改变的地方还是很多的,先记一下差分信号在FPGA中的收发管脚定义和配置.以LVDS信号为例吧. 在7 Serie ...
- ACM-最优配餐
题目描述: 最优配餐 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 栋栋最近开了一家餐饮连锁店,提供外卖服务.随着连锁店越来越多,怎么合理的给客户送餐成为了一个急需解决的问 ...
- 创建springboot2.1项目运行报错
刚创建好一个项目,运行就报错:in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging ...
- nodejs 文件路径问题
fs.stat() 是 获取 本目录下 文件信息 的方法 .如果使用要加上绝对路径.不然会出问题.例: 解决方法