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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

golang 在container包下提供了list双链表、heap、ring等容器结构 !Pasted image 20231225085517.png

一、list

golang 中实现的list为双向链表。双向链表一般用于经常堆头部和尾部进行增删的场景同时它不需要在一开始初始化它的容量它的容量随着使用动态变化扩大or缩小。 核心数据结构(Element、List)

// 链表的一个元素
type Element struct {
   next, prev *Element // 前后指针
   list *List // 所属链表
   Value any // 值
}
// 链表
type List struct {
   root Element // 哨兵元素
   len  int     // 链表元素个数
}

!Pasted image 20231225170420.png

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)  
}

三、ring