|
|
golang 在container包下提供了list(双链表)、heap(堆)、ring(环)等容器结构
|
|
|
![[Pasted image 20231225085517.png]]
|
|
|
# 一、list
|
|
|
golang 中实现的list为双向链表。双向链表一般用于经常堆头部和尾部进行增删的场景,同时它不需要在一开始初始化它的容量,它的容量随着使用动态变化(扩大or缩小)。
|
|
|
核心数据结构(Element、List):
|
|
|
```golang
|
|
|
// 链表的一个元素
|
|
|
type Element struct {
|
|
|
next, prev *Element // 前后指针
|
|
|
list *List // 所属链表
|
|
|
Value any // 值
|
|
|
}
|
|
|
```
|
|
|
|
|
|
```golang
|
|
|
// 链表
|
|
|
type List struct {
|
|
|
root Element // 哨兵元素
|
|
|
len int // 链表元素个数
|
|
|
}
|
|
|
```
|
|
|
![[Pasted image 20231225170420.png]]
|
|
|
|
|
|
## 1.初始化
|
|
|
```golang
|
|
|
package main
|
|
|
|
|
|
import (
|
|
|
"container/list"
|
|
|
"fmt"
|
|
|
)
|
|
|
func main()
|
|
|
// 使用list.New()直接初始化
|
|
|
l1 := list.New()
|
|
|
l1.PushFront(1)
|
|
|
fmt.Println(l1.Front().Value) // 1
|
|
|
|
|
|
// 使用list.List{}延迟初始化
|
|
|
l2 := list.List{}
|
|
|
l2.PushFront(2)
|
|
|
fmt.Println(l2.Front().Value) // 2
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 2.常用API
|
|
|
+ PushFront 链表头部添加元素
|
|
|
+ PushBack 尾部添加元素
|
|
|
+ PushFrontList 链表头部插入链表
|
|
|
+ PushBackList 尾部插入链表
|
|
|
+ Front 获取头部元素
|
|
|
+ Back 获取尾元素
|
|
|
+ Len 获取长度
|
|
|
+ InsertBefore 某个元素前插入
|
|
|
+ InsertAfter 某个元素后插入
|
|
|
+ MoveBefore 移动元素到某个元素前面
|
|
|
+ MoveAfter 移动元素到某个元素后面
|
|
|
+ MoveToFront 移动元素到头部
|
|
|
+ MoveToBack 移动元素到尾部
|
|
|
|
|
|
# 二、heap
|
|
|
堆是一颗完全二叉树,按照比较规则不同,分为最大堆和最小堆。以最小堆为例,父节点总是比子节点小。
|
|
|
堆的下标公式:
|
|
|
parent(i)=floor((i-1)/2) 向下取整
|
|
|
left(i)=2i+1
|
|
|
right(i)=2i+2
|
|
|
|
|
|
golang 提供了最小堆算法,其中包含5个接口需要开发者自行实现(**作为官方包,Golang 希望提供给大家一种简单的接入方式,官方提供好算法的内核,大家接入就 ok。采用的是定义一个接口,开发者来实现的方式**)
|
|
|
```golang
|
|
|
type Interface interface {
|
|
|
sort.Interface
|
|
|
Push(x any) // 入堆
|
|
|
Pop() any // 出堆
|
|
|
}
|
|
|
|
|
|
type Interface interface {
|
|
|
Len() int //堆大小
|
|
|
Less(i, j int) bool //比较
|
|
|
Swap(i, j int) //交换
|
|
|
}
|
|
|
```
|
|
|
## 例一:最小堆
|
|
|
```golang
|
|
|
package mycontainer
|
|
|
|
|
|
type IntHeap []int
|
|
|
|
|
|
// Push IntHeap全局共享切只有一个,所以需要对类型本身进行操作,所以使用指针
|
|
|
func (h *IntHeap) Push(x any) {
|
|
|
//append需要传入切片,切片是引用传递所以需要*h,
|
|
|
*h = append(*h, x.(int))
|
|
|
}
|
|
|
|
|
|
// Pop
|
|
|
//
|
|
|
// @Description: 从数组移除一个元素
|
|
|
// @receiver h
|
|
|
// @return any
|
|
|
func (h *IntHeap) Pop() any {
|
|
|
old := *h
|
|
|
n := len(old)
|
|
|
x := old[n-1]
|
|
|
*h = old[0 : n-1]
|
|
|
return x
|
|
|
}
|
|
|
|
|
|
// Len
|
|
|
//
|
|
|
// @Description: 计算元素大小
|
|
|
// @receiver h
|
|
|
// @return int
|
|
|
func (h IntHeap) Len() int {
|
|
|
return len(h)
|
|
|
}
|
|
|
|
|
|
// Less
|
|
|
//
|
|
|
// @Description: 比较大小
|
|
|
// @receiver h
|
|
|
// @param i
|
|
|
// @param j
|
|
|
// @return bool
|
|
|
func (h IntHeap) Less(i, j int) bool {
|
|
|
return h[i] < h[j]
|
|
|
}
|
|
|
|
|
|
// Swap
|
|
|
//
|
|
|
// @Description: 交换i,j下标元素
|
|
|
// @receiver h
|
|
|
// @param i
|
|
|
// @param j
|
|
|
func (h IntHeap) Swap(i, j int) {
|
|
|
h[i], h[j] = h[j], h[i]
|
|
|
}
|
|
|
|
|
|
|
|
|
// TestIntHeap
|
|
|
//
|
|
|
// @Description: 测试自定义堆
|
|
|
// @param t
|
|
|
func TestIntHeap(t *testing.T) {
|
|
|
//因为pop和push方法需要传入指针
|
|
|
h := &myc.IntHeap{7, 9, 10}
|
|
|
print(h)
|
|
|
//堆初始化,用于构建二叉树
|
|
|
heap.Init(h)
|
|
|
//添加元素
|
|
|
heap.Push(h, 3)
|
|
|
fmt.Printf("minimum: %d\n", (*h)[0])
|
|
|
for h.Len() > 0 {
|
|
|
fmt.Printf("%d ", heap.Pop(h))
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 例二:优先队列
|
|
|
```golang
|
|
|
type Item struct {
|
|
|
value string
|
|
|
priority int
|
|
|
index int
|
|
|
}
|
|
|
|
|
|
type PriorityQueue []*Item
|
|
|
|
|
|
func (p *PriorityQueue) Push(x any) {
|
|
|
n := len(*p)
|
|
|
item := x.(*Item)
|
|
|
item.index = n
|
|
|
*p = append(*p, item)
|
|
|
}
|
|
|
|
|
|
func (p *PriorityQueue) Pop() any {
|
|
|
old := *p
|
|
|
n := len(old)
|
|
|
item := old[n-1]
|
|
|
item.index = -1
|
|
|
*p = old[0 : n-1]
|
|
|
return item
|
|
|
}
|
|
|
|
|
|
func (p PriorityQueue) Len() int {
|
|
|
return len(p)
|
|
|
}
|
|
|
|
|
|
func (p PriorityQueue) Less(i, j int) bool {
|
|
|
return p[i].priority > p[j].priority
|
|
|
}
|
|
|
|
|
|
func (p PriorityQueue) Swap(i, j int) {
|
|
|
p[i], p[j] = p[j], p[i]
|
|
|
p[i].index = i
|
|
|
p[j].index = j
|
|
|
}
|
|
|
|
|
|
// 更新元素优先级
|
|
|
func (p *PriorityQueue) update(item *Item, value string, priority int) {
|
|
|
item.value = value
|
|
|
item.priority = priority
|
|
|
//二叉堆重排序
|
|
|
heap.Fix(p, item.index)
|
|
|
}
|
|
|
```
|
|
|
# 三、ring |