基于源码Golang1.14.2
堆
type Interface interface {
sort.Interface
Push(x interface{})
Pop() interface{} // remove and return element Len() - 1.
}
其中sort.Interface如下图,具体介绍会在Sort里面介绍
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
从以上的结构可以看出堆的结构体需要实现Push,Pop,Len,Less,Swap这5个接口。
在这里我要着重强调一下heap不一定是小顶堆(看到很多博客上说都是小顶堆),如果Less反着写就可以当大顶堆用
源码最重要的是如下两个函数
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
}
up: 对一个节点进行冒泡,如果次节点Less它的父节点,那么就Swap两者的位置。
down: 对一个节点进行下沉,下沉到左右子树最适合的节点,并依次交换中途的节点。最后如果下沉了则返回true.
Push(h Interface, x interface{}) //加入元素
Pop(h Interface) interface{} //移除最后一个元素
Remove(h Interface, i int) interface{} //移除第i个元素
Fix(h Interface, i int) //修改了某个元素的值后,需要重排堆
双向链表
type Element struct {
next, prev *Element
list *List
Value interface{}
}
func (e *Element) Next() *Element {
if p := e.next; e.list != nil && p != &e.list.root {
return p
}
return nil
}
func (e *Element) Prev() *Element {
if p := e.prev; e.list != nil && p != &e.list.root {
return p
}
return nil
}
type List struct {
root Element
len int
}
从这个结构可以看出是一个双向链表,root节点是表头,也就是最后一个节点的next指向root,最前面的一个节点的prev也指向root,不过p != &e.list.root让我们感知不到表头。
其他方法
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{} // 删除某个元素
双向环
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 个元素
下面我着重讲一下Link和UnLink
Link
func (r *Ring) Link(s *Ring) *Ring {
n := r.Next()
if s != nil {
p := s.Prev()
r.next = s
s.prev = r
n.prev = p
p.next = n
}
return n
}
r为环当前节点,n为后一个节点。s为另一个环当前节点,p为s的前一个节点。
如果r和s不同环,连接方式是:r连接s,p连接n,然后返回n节点。
如果r和s同环,连接方式是:r连接s,同时p和n形成一个换,返回子环,同时指针指向n。
Unlink
func (r *Ring) Unlink(n int) *Ring {
if n <= 0 {
return nil
}
return r.Link(r.Move(n + 1))
}
调用Link函数,返回的内容是从原来r上剥离出来的环,这个环的节点数为n。