读完Golang源码之Container

基于源码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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值