首先是环形链表的结构与初初始化
type Ring struct {
next, prev *Ring
Value interface{} // for use by client; untouched by this library
}
func (r *Ring) init() *Ring {
r.next = r
r.prev = r
return r
}
环形链表是有n个带前后指针的节点形成的,他可以正序也可以倒序遍历。
他的初始化是指定一个节点,然后把next和prev都指向自己。
然后是新建一个双向环形链表,传入一个长度,返回链表指针。该链表里面的节点都是空的,可以存放任何东西(因为是空接口)
func New(n int) *Ring {
if n <= 0 {
return nil
}
r := new(Ring)
p := r
for i := 1; i < n; i++ {
p.next = &Ring{prev: p}
p = p.next
}
p.next = r
r.prev = p
return 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 := 0
if r != nil {
n = 1
for 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 = s
s.prev = r
n.prev = p
p.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 = mtf
this.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
}
}