# 数据结构和算法

# sort

该包实现了四种基本排序算法:插入排序、归并排序、堆排序和快速排序。 但是这四种排序方法只被用于 sort 包内部使用。

所以在对数据集合排序时不必考虑应当选择哪一种排序方法,想要对数据集合进行排序,只要实现 sort.Interface 定义的三个方法:

  1. 获取数据集合长度的 Len () 方法
  2. 比较两个元素大小的 Less () 方法
  3. 交换两个元素位置的 Swap () 方法

sort 包会根据实际数据自动选择高效的排序算法。
除此之外,为了方便对常用数据类型的操作,sort 包提供了对 [] int 切片、[] float64 切片和 [] string 切片完整支持,主要包括:

  • 对基本数据类型切片的排序支持
  • 基本数据元素查找
  • 判断基本数据类型切片是否已经排好序
  • 对排好序的数据集合逆序

# Interface

type Interface interface {
	// Len 获取数据集合元素个数
	Len() int
    // Less 返回索引 i 的元素是否必须排在索引 j 的元素之前。
	Less(i, j int) bool
	// Swap 交换索引 i 和 j 的元素。
	Swap(i, j int)
}

实现了这三个方法后,即可调用该包的 Sort () 方法进行排序。

# Sort

Sort () 方法定义如下:

// Sort 按 Less 方法确定的升序对数据进行排序。
// 调用一次 data.Len 以确定对 data.Less 和 data.Swap 的 n 次调用和 O (n*log (n)) 次调用。 
// 不保证排序是稳定的。
func Sort(data Interface) {
	n := data.Len()
	if n <= 1 {
		return
	}
	limit := bits.Len(uint(n))
	pdqsort(data, 0, n, limit)
}

判断数据集合是否已经排好顺序,该方法的内部实现依赖于我们自己实现的 Len () 和 Less () 方法:

func IsSorted(data Interface) bool {
    n := data.Len()
    for i := n - 1; i > 0; i-- {
        if data.Less(i, i-1) {
            return false
        }
    }
    return true
}

对学生成绩排序的 demo :

package main
import (
	"fmt"
	"sort"
)
// 学生成绩结构体
type StuScore struct {
	name  string // 姓名
	score int    // 成绩
}
type StuScores []StuScore
// Len()
func (s StuScores) Len() int {
	return len(s)
}
// Less (): 成绩将有低到高排序
func (s StuScores) Less(i, j int) bool {
	return s[i].score < s[j].score
}
// Swap()
func (s StuScores) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func main() {
	stus := StuScores{
		{"alan", 95},
		{"hikerell", 91},
		{"acmfly", 96},
		{"leao", 90},
	}
	// 打印未排序的 stus 数据
	fmt.Println("\nDefault:\n", stus)
	//StuScores 已经实现了 sort.Interface 接口,所以可以调用 Sort 函数进行排序
	sort.Sort(stus)
	// 判断是否已经排好顺序,将会打印 true
	fmt.Println("\nIS Sorted?\n", sort.IsSorted(stus))
	// 打印排序后的 stus 数据
	fmt.Println("\nSorted:\n", stus)
}

输出

Default:
 [{alan 95} {hikerell 91} {acmfly 96} {leao 90}]
IS Sorted?
 true
Sorted:
 [{leao 90} {hikerell 91} {alan 95} {acmfly 96}]

# Reverse

提供了 Reverse () 方法,可以允许将数据按 Less () 定义的排序方式逆序排序,而不必修改 Less () 代码。方法定义如下:

// 定义了一个 reverse 结构类型,嵌入 Interface 接口
type reverse struct {
	Interface
}
// Less 返回与实现的 Less 方法相反的结果。
func (r reverse) Less(i, j int) bool {
	return r.Interface.Less(j, i)
}
// Reverse 返回数据的相反顺序。
func Reverse(data Interface) Interface {
	return &reverse{data}
}

了解内部原理后,可以在学生成绩排序示例中使用 Reverse () 来实现成绩升序排序

demo:

func main() {
	stus := StuScores{
		{"alan", 95},
		{"hikerell", 91},
		{"acmfly", 96},
		{"leao", 90},
	}
	sort.Sort(sort.Reverse(stus))
	fmt.Println("\nSorted:\n", stus)
}

该方法会使用 “二分查找” 算法来找出能使 f (x)(0<=x<n) 返回 ture 的最小值 i。

前提条件 :
f (x)(0<=x<i) 均返回 false,
f (x)(i<=x<n) 均返回 ture。

如果不存在 i 可以使 f (i) 返回 ture, 则返回 n。

func Search(n int, f func(int) bool) int {
	// 定义 f (-1) == false and f (n) == true.
	// 不变式: f (i-1) == false, f (j) == true.
	i, j := 0, n
	for i < j {
		h := int(uint(i+j) >> 1) // 避免计算 h 时溢出
		// i ≤ h < j
		if !f(h) {
			i = h + 1 // 保留 f (i-1) == false 
		} else {
			j = h // 保留 f (j) == true
		}
	}
	// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
	return i
}

官方还给了一个猜数字的 demo

func GuessingGame() {
	var s string
	fmt.Printf("Pick an integer from 0 to 100.\n")
	answer := sort.Search(100, func(i int) bool {
		fmt.Printf("Is your number <= %d? ", i)
		fmt.Scanf("%s", &s)
		return s != "" && s[0] == 'y'
	})
	fmt.Printf("Your number is %d.\n", answer)
}

# IntSlice, Float64Slice, StringSlice

sort 包已经支持的内部数据类型排序

sort 包原生支持 [] int、[] float64 和 [] string 三种内建数据类型切片的排序操作,即不必我们自己实现相关的 Len ()、Less () 和 Swap () 方法。

1. IntSlice 类型及 [] int 排序

由于 [] int 切片排序内部实现及使用方法与 [] float64 和 [] string 类似,所以只详细描述该部分。

sort 包定义了一个 IntSlice 类型,并且实现了 sort.Interface 接口:

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] }
//IntSlice 类型定义了 Sort () 方法,包装了 sort.Sort () 函数
func (p IntSlice) Sort() { Sort(p) }
//IntSlice 类型定义了 SearchInts () 方法,包装了 SearchInts () 函数
func (p IntSlice) Search(x int) int { return SearchInts(p, x) }
// SearchInts 搜索
func SearchInts(a []int, x int) int {
	return Search(len(a), func(i int) bool { return a[i] >= x })
}
//sort.Ints () 方法使用了该 IntSlice 类型:
func Ints(a []int) { Sort(IntSlice(a)) }

对 [] int 切片排序更常使用 sort.Ints (),而不是直接使用 IntSlice 类型:

func main() {
	s := []int{5, 2, 6, 3, 1, 4} // 未排序的切片数据
	sort.Ints(s)
	fmt.Println(s) // 将会输出 [1 2 3 4 5 6]
}

如果要查找整数 x 在切片 a 中的位置,相对于前面提到的 Search () 方法,sort 包提供了 SearchInts ():

注意,SearchInts () 的使用条件为:切片已经升序排序

func main() {
	s := []int{5, 2, 6, 3, 1, 4} // 未排序的切片数据
	sort.Ints(s)
	fmt.Println(sort.SearchInts(s, 2)) // 1
}

2. Float64Slice 类型及 [] float64 排序

实现与 Ints 类似,只看一下其内部实现:

type Float64Slice []float64
func (p Float64Slice) Len() int           { return len(p) }
func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || isNaN(p[i]) && !isNaN(p[j]) }
func (p Float64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Float64Slice) Sort() { Sort(p) }
func (p Float64Slice) Search(x float64) int { return SearchFloat64s(p, x) }

与 Sort ()、IsSorted ()、Search () 相对应的三个方法:

func Float64s(a []float64)  
func Float64sAreSorted(a []float64) bool
func SearchFloat64s(a []float64, x float64) int

要说明一下的是,在上面 Float64Slice 类型定义的 Less 方法中,有一个内部函数 isNaN ()。 isNaN () 与 math 包中 IsNaN () 实现完全相同,sort 包之所以不使用 math.IsNaN (),完全是基于包依赖性的考虑,应当看到,sort 包的实现不依赖与其他任何包。

3. StringSlice 类型及 [] string 排序

两个 string 对象之间的大小比较是基于 “字典序” 的。

实现与 Ints 类似,只看一下其内部实现:

type StringSlice []string
func (p StringSlice) Len() int           { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p StringSlice) Sort() { Sort(p) }
func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }

与 Sort ()、IsSorted ()、Search () 相对应的三个方法:

func Strings(a []string)
func StringsAreSorted(a []string) bool
func SearchStrings(a []string, x string) int

3. StringSlice 类型及 [] string 排序

两个 string 对象之间的大小比较是基于 “字典序” 的。

实现与 Ints 类似,只看一下其内部实现:

type StringSlice []string
func (p StringSlice) Len() int           { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p StringSlice) Sort() { Sort(p) }
func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }

与 Sort ()、IsSorted ()、Search () 相对应的三个方法:

func Strings(a []string)
func StringsAreSorted(a []string) bool
func SearchStrings(a []string, x string) int

# []interface

只要实现了 sort.Interface 接口,即可通过 sort 包内的函数完成排序,查找等操作。

并且 sort 包已经帮我们把 []int , []float64 , []string 三种类型都实现了该接口,我们可以方便的调用。但是这种用法对于其它数据类型的 slice 不友好,可能我们需要为大量的 struct 定义一个单独的 [] struct 类型,再为其实现 sort.Interface 接口,类似这样:

type Person struct {
    Name string
    Age  int
}
type Persons []Person
func (p Persons) Len() int {
    panic("implement me")
}
func (p Persons) Less(i, j int) bool {
    panic("implement me")
}
func (p Persons) Swap(i, j int) {
    panic("implement me")
}

因为排序涉及到比较两个变量的值,而 struct 可能包含多个属性,程序并不知道你想以哪一个属性或哪几个属性作为衡量大小的标准。

如果能帮助程序完成比较,并将结果返回, sort 包内的方法就可以完成排序,判断,查找等。sort 包提供了以下函数:

func Slice(slice interface{}, less func(i, j int) bool) 
func SliceStable(slice interface{}, less func(i, j int) bool) 
func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool 
func Search(n int, f func(int) bool) int

通过函数签名可以看到,排序相关的三个函数都接收 []interface ,并且需要传入一个比较函数,用于为程序比较两个变量的大小,因为函数签名和作用域的原因,这个函数只能是 匿名函数

1. sort.Slice

该函数完成 [] interface 的排序

demo:

func main() {
	people := []struct {
		Name string
		Age  int
	}{
		{"Gopher", 7},
		{"Alice", 55},
		{"Vera", 24},
		{"Bob", 75},
	}
    // 按年龄升序排序
	sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age }) 
	fmt.Println("Sort by age:", people)
    //  Sort by age: [{Gopher 7} {Vera 24} {Alice 55} {Bob 75}]
}

2. sort.SliceStable

该函数完成 [] interface 的稳定排序,

demo:

func main() {
	people := []struct {
		Name string
		Age  int
	}{
		{"Gopher", 7},
		{"Alice", 55},
		{"Vera", 24},
		{"Bob", 75},
	}
	// 按年龄降序排序
	sort.SliceStable(people, func(i, j int) bool { return people[i].Age > people[j].Age })
	fmt.Println("Sort by age:", people)
    // By age: [{Bob 75} {Alice 55} {Vera 24} {Gopher 7}]
}

3. sort.SliceIsSorted

该函数判断 [] interface 是否为有序

demo:

func main() {
	people := []struct {
		Name string
		Age  int
	}{
		{"Gopher", 7},
		{"Alice", 55},
		{"Vera", 24},
		{"Bob", 75},
	}
	sort.Slice(people, func(i, j int) bool { return people[i].Age > people[j].Age })
	fmt.Println("Sort by age:", people)
	// Sort by age: [{Bob 75} {Alice 55} {Vera 24} {Gopher 7}]
	fmt.Println("Sorted:", sort.SliceIsSorted(people, func(i, j int) bool { return people[i].Age < people[j].Age }))
	// Sorted: false
}

# container

该包实现了三个复杂的数据结构:堆,链表,环。

# Heap

堆,这里的堆使用的数据结构是最小二叉树,即根节点比左边子树和右边子树的所有值都小。 go 的堆包只是实现了一个接口:

type Interface interface {
    sort.Interface
    Push(x interface{}) // add x as element Len()
    Pop() interface{}   // remove and return element Len() - 1.
}
// 交换节点的操作
func up(h Interface, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !h.Less(j, i) {
			break
		}
		h.Swap(i, j)
		j = i
	}
}
func down(h Interface, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && h.Less(j2, j1) {
			j = j2 // = 2*i + 2  // right child
		}
		if !h.Less(j, i) {
			break
		}
		h.Swap(i, j)
		i = j
	}
	return i > i0
}

官方的 demo:

type IntHeap []int
func (h IntHeap) Len() int           { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
    *h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
    old := *h
    n := len(old)
    x := old[n-1]
    *h = old[0 : n-1]
    return x
}

# List

链表,一个有 prev 和 next 指针的数组。它维护两个 type,(注意,这里不是 interface)

type Element struct {
    next, prev *Element  // 上一个元素和下一个元素
    list *List  // 元素所在链表
    Value interface{}  // 元素
}
type List struct {
    root Element  // 链表的根元素
    len  int      // 链表的长度
}

方法:

type Element
    func (e *Element) Next() *Element
    func (e *Element) Prev() *Element
type List
    func New() *List
    func (l *List) Back() *Element   // 最后一个元素
    func (l *List) Front() *Element  // 第一个元素
    func (l *List) Init() *List  // 链表初始化
    func (l *List) InsertAfter(v interface{}, mark *Element) *Element // 在某个元素后插入
    func (l *List) InsertBefore(v interface{}, mark *Element) *Element  // 在某个元素前插入
    func (l *List) Len() int // 在链表长度
    func (l *List) MoveAfter(e, mark *Element)  // 把 e 元素移动到 mark 之后
    func (l *List) MoveBefore(e, mark *Element)  // 把 e 元素移动到 mark 之前
    func (l *List) MoveToBack(e *Element) // 把 e 元素移动到队列最后
    func (l *List) MoveToFront(e *Element) // 把 e 元素移动到队列最头部
    func (l *List) PushBack(v interface{}) *Element  // 在队列最后插入元素
    func (l *List) PushBackList(other *List)  // 在队列最后插入接上新队列
    func (l *List) PushFront(v interface{}) *Element  // 在队列头部插入元素
    func (l *List) PushFrontList(other *List) // 在队列头部插入接上新队列
    func (l *List) Remove(e *Element) interface{} // 删除某个元素

demo:

func main() {
	list := list.New()
	list.PushBack(1)
	list.PushBack(2)
	fmt.Printf("len: %v\n", list.Len())
	fmt.Printf("first: %#v\n", list.Front())
	fmt.Printf("second: %#v\n", list.Front().Next())
    
    func main() {
	list := list.New()
	list.PushBack(1)
	list.PushBack(2)
	fmt.Printf("len: %v\n", list.Len())
	fmt.Printf("first: %#v\n", list.Front())
	fmt.Printf("second: %#v\n", list.Front().Next())
	// len: 2
	// first: &list.Element{next:(*list.Element)(0xc0000a01b0), prev:(*list.Element)(0xc0000a0150), list:(*list.List)(0xc0000a0150), Value:1}
	// second: &list.Element{next:(*list.Element)(0xc0000a0150), prev:(*list.Element)(0xc0000a0180), list:(*list.List)(0xc0000a0150), Value:2}
}

# Ring

环的结构有点特殊,环的尾部就是头部,所以每个元素实际上就可以代表自身的这个环。 它不需要像 list 一样保持 list 和 element 两个结构,只需要保持一个结构就行。

type Ring struct {
    next, prev *Ring
    Value      interface{}
}

方法:

type Ring
    func New(n int) *Ring  // 初始化环
    func (r *Ring) Do(f func(interface{}))  // 循环环进行操作
    func (r *Ring) Len() int // 环长度
    func (r *Ring) Link(s *Ring) *Ring // 连接两个环
    func (r *Ring) Move(n int) *Ring // 指针从当前元素开始向后移动或者向前(n 可以为负数)
    func (r *Ring) Next() *Ring // 当前元素的下个元素
    func (r *Ring) Prev() *Ring // 当前元素的上个元素
    func (r *Ring) Unlink(n int) *Ring // 从当前元素开始,删除 n 个元素

demo :

func main() {
	ring := ring.New(3)
	for i := 1; i <= 3; i++ {
		ring.Value = i
		ring = ring.Next()
	}
	// 计算 1+2+3
	s := 0
	ring.Do(func(p interface{}) {
		s += p.(int)
	})
	fmt.Println("sum is", s)
	// sum is 6
}
-->