funcInit(h Interface) { // heapify n := h.Len() for i := n/2 - 1; i >= 0; i-- { // 便利所有的节点,满足根节点在树中最大或者最小。 down(h, i, n) } }
// 向上保证,满足h.Less的判断 funcup(h Interface, j int) { for { i := (j - 1) / 2// parent if i == j || !h.Less(j, i) { break } h.Swap(i, j) j = i } }
// 向下保证,满足h.Less的判断 funcdown(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 }
初始化、压入、弹出、删除的过程都会通过向上、向下判断,修正树结构。
在优先级队列中的使用方式,与上面的例子类似,区别是优先级可能会被修改,就会使用到Fix。
List
链表,而且是一种双向链表得数据结构
结构体如下
1 2 3 4 5 6 7 8 9 10 11 12
// 链表中的元素 type Element struct { next, prev *Element // 下一个、上一个节点 list *List // 数组 Value any // 值 }
// 链表结构体 type List struct { root Element // sentinel list element, only &root, root.prev, and root.next are used lenint// current list length excluding (this) sentinel element }
l := list.New() rand.Seed(time.Now().UnixNano()) for i := 0; i < 10; i++ { s := student{ id: i, age: rand.Intn(100), } l.PushFront(s) // 压入数据 } for e := l.Front(); e.Next() != nil; e = l.Front() { fmt.Println(l.Remove(e)) }
Ring
环形链表,也是一个双向的。
数据结构
1 2 3 4
type Ring struct { next, prev *Ring // 前后节点 Value any // for use by client; untouched by this library }
r := ring.New(5) for i := 0; i < 5; i++ { r.Value = i r = r.Next() } for i := 0; i < 7; i++ { fmt.Println(r.Value) r = r.Next() } r.Do(func(a any) { fmt.Printf("do : %v\n", a) })
约瑟夫问题:在一个环中,从1开始计数,计算到某个数时,标识这个数
隔4个标记为删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
r := ring.New(10) for i := 0; i < 10; i++ { r.Value = i r = r.Next() } for { for i := 0; i < 4; i++ { r = r.Next() } if r.Value == -1 { break } r.Value = -1 }
r.Do(func(a any) { fmt.Printf("%v\n", a) })
或者,在环中删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
r := ring.New(10) for i := 0; i < 10; i++ { r.Value = i r = r.Next() } for { for i := 0; i < 3; i++ { r = r.Next() } if r.Len() == 1 { break } r.Unlink(1) }