当前位置: 代码迷 >> 综合 >> go Ring(环形链表)源码解读与应用
  详细解决方案

go Ring(环形链表)源码解读与应用

热度:46   发布时间:2023-12-03 22:38:47.0

首先是环形链表的结构与初初始化

type Ring struct {next, prev *RingValue      interface{} // for use by client; untouched by this library
}func (r *Ring) init() *Ring {r.next = rr.prev = rreturn r
}

 

 环形链表是有n个带前后指针的节点形成的,他可以正序也可以倒序遍历。

他的初始化是指定一个节点,然后把next和prev都指向自己。

 

然后是新建一个双向环形链表,传入一个长度,返回链表指针。该链表里面的节点都是空的,可以存放任何东西(因为是空接口)

func New(n int) *Ring {if n <= 0 {return nil}r := new(Ring)p := rfor i := 1; i < n; i++ {p.next = &Ring{prev: p}p = p.next}p.next = rr.prev = preturn r
}

 

他的Next() 和 prev()方法也很简单,返回他后一个元素和前一个元素的指针。

// Next returns the next ring element. r must not be empty.
func (r *Ring) Next() *Ring {if r.next == nil {return r.init()}return r.next
}// Prev returns the previous ring element. r must not be empty.
func (r *Ring) Prev() *Ring {if r.next == nil {return r.init()}return r.prev
}

 move方法。只是简单的指针移动

func (r *Ring) Move(n int) *Ring {if r.next == nil {return r.init()}switch {case n < 0:for ; n < 0; n++ {r = r.prev}case n > 0:for ; n > 0; n-- {r = r.next}}return r
}

假设当前指针指向1,顺时针方向为next方向,则move(1),就是把指针移到2位置,move(-1),就是把指针移到7位置

 

获取长度(注意for循环里第二个条件p!=r,判断是否是遍历的起始节点)

func (r *Ring) Len() int {n := 0if r != nil {n = 1for p := r.Next(); p != r; p = p.next {n++}}return n
}

do方法是传入一个方法,然后让每个节点都去运行这个方法

func (r *Ring) Do(f func(interface{})) {if r != nil {f(r.Value)for p := r.Next(); p != r; p = p.next {f(p.Value)}}
}

 link是吧两个不同的环形链表连接起来,如果r和s在同一个环形链表里,则会把r与s之间沿着next方向的元素移除。

unc (r *Ring) Link(s *Ring) *Ring {n := r.Next()if s != nil {p := s.Prev()// Note: Cannot use multiple assignment because// evaluation order of LHS is not specified.r.next = ss.prev = rn.prev = pp.next = n}return n
}

 

unlick是把当前节点之后的n个节点移除,调用的是link方法,原理可以参考上图同一个环形链表的link方法

func (r *Ring) Unlink(n int) *Ring {if n <= 0 {return nil}return r.Link(r.Move(n + 1))
}

应用场景:

交易所的历史成交交易。可以存在环形链表里,当有新的交易成交时,把指针像下移一个,然后把旧的成交订单替换掉。(这边只是在内存里存了一定数量的最新成交订单,所有会有覆盖的情况,当链表长度为50,此时有新的成交订单进来时,会把最旧的那个订单替换掉)


r := this.currentMtf.Next() 
r.Value = mtfthis.currentMtf = r

查询历史订单

//do方法链上每个节点都会执行。这边做的只是封装工作,和重点无关,同时,这边像next方向,
//把成交订单添加入items。但是当前指针的订单是最新的,currentMtf.Next()就是最旧的订单或者nil
//所有items是按旧到新排序
match.currentMtf.Next().Do(func(data interface{}) {if data != nil {mtf := data.(*msq.MtfData)item := TradeItem{mtf.MatchTime, mtf.Price, mtf.Amount, mtf.IsBuy}items = append(items, item)}
})//因为要显示的订单成交情况是最新的订单再到旧的,所有再次把他数据倒过来
for i := len(items) - 1; i >= 0; i-- {depth--info.Trades = append(info.Trades, items[i])if depth == 0 {break}
}