环状双向链表 (无哨兵)git
相较于 List , ring 由于不须要哨兵快速找到头尾, 因此只有一个 struct ring
(环)github
type Ring struct {
// 先后节点
next, prev *Ring
Value interface{}
}
复制代码
建立一个环, 使用 New 函数, 建立一个有 n 个容量的环闭包
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
}
复制代码
同时提供 Len() 函数, 获取当前 ring 的容量函数
func (r *Ring) Len() int {
n := 0
if r != nil {
n = 1
// 即时的去遍历一次 ring 获取当前长度
for p := r.Next(); p != r; p = p.next {
n++
}
}
return n
}
复制代码
为在 ring 中移动当前操做的指针, 提供了 move 方法, 支持正向移动和反方向移动 (向左或向右移动)ui
func (r *Ring) Move(n int) *Ring {
if r.next == nil {
/* 避免 a:=&ring.Ring{} 而后直接拿来用而没有初始化从而报错的状况 */
return r.init()
}
switch {
case n < 0:
// 负数加到 0
for ; n < 0; n++ {
r = r.prev
}
case n > 0:
// 正数减到 0
for ; n > 0; n-- {
r = r.next
}
}
return r
}
复制代码
也能够给加入环节点或者删除环节点 (相似于)lua
func (r *Ring) Link(s *Ring) *Ring {
/** ┌-----------------------┐ ∨ ∨ a <---> r <---> b <---> c ^ add s ___ OR __ ┌-----------------------┐ ∨ ∨ a <---> r <---> b <---> c ^ ┌-----------------------┐ ∨ ∨ d <---> f <---> s <---> g ^ s will add after r */
/* ┌-----------------------┐ ∨ n| ∨ a <---> r <---> b <---> c ┌-----------------------┐ ∨ ∨ d <---> f <---> s <---> g */
n := r.Next()
if s != nil {
/* ┌-----------------------┐ ∨ n| ∨ a <---> r <---> b <---> c ┌-----------------------┐ ∨ p| ∨ d <---> f <---> s <---> g */
p := s.Prev()
// Note: Cannot use multiple assignment because
// evaluation order of LHS is not specified.
/* ┌-----------------------┐ ∨ n| ∨ a <---> r <---- b <---> c └----┐ | p| └--↓ d <---> f <---> s <---> g ^ ^ └-----------------------┘ */
r.next = s
/* ┌-----------------------┐ ∨ n| ∨ a <---> r <---- b <---> c ↑----┐ | p| └--↓ d <---> f ----> s <---> g ^ ^ └-----------------------┘ */
s.prev = r
/* ┌-----------------------┐ ∨ n| ∨ a <---> r b <---> c ↑----┐ | ┌----┼--┘ p| └--↓ d <---> f ----> s <---> g ^ ^ └-----------------------┘ */
n.prev = p
/* ┌-----------------------┐ ∨ n| ∨ a <---> r b <---> c ↑----┐ ↑ ┌----┼--┘ p↓ └--↓ d <---> f s <---> g ^ ^ └-----------------------┘ */
p.next = n
/* ┌-------------------------------------------------------┐ ∨ p| n| ∨ a <---> r <---> s <---> g <---> d <---> f <---> b <---> c */
}
return n
}
复制代码
因此最终是将 r 节点和 s 节点进行连接, 将 r 的后驱节点和 s 的前驱节点进行连接, 组成一个新的双向链表实现的环spa
而 Unlink() 方法则是 调用的 link 方法并作了一些变化指针
func (r *Ring) Unlink(n int) *Ring {
if n <= 0 {
return nil
}
return r.Link(
// 获取 r 的 n 个节点以后的那个 b 节点
r.Move(n + 1)
// 而后将 当前的 r 节点和 b 节点链接起来
// 则中间的这些节点至关于从环中被排除掉
)
}
复制代码
最后, Ring 还提供一个 Do() 方法, 容许使用闭包函数遍历 整个 Ringcode
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)
}
}
}
复制代码
欢迎到 github.com/Kuri-su/KBl… 开 Issue 讨论ip