You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.7 KiB
4.7 KiB
golang 在container包下提供了list(双链表)、heap(堆)、ring(环)等容器结构
!
一、list
golang 中实现的list为双向链表。双向链表一般用于经常堆头部和尾部进行增删的场景,同时它不需要在一开始初始化它的容量,它的容量随着使用动态变化(扩大or缩小)。 核心数据结构(Element、List):
// 链表的一个元素
type Element struct {
next, prev *Element // 前后指针
list *List // 所属链表
Value any // 值
}
// 链表
type List struct {
root Element // 哨兵元素
len int // 链表元素个数
}
1.初始化
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。采用的是定义一个接口,开发者来实现的方式)
type Interface interface {
sort.Interface
Push(x any) // 入堆
Pop() any // 出堆
}
type Interface interface {
Len() int //堆大小
Less(i, j int) bool //比较
Swap(i, j int) //交换
}
例一:最小堆
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))
}
}
例二:优先队列
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)
}