環狀雙向鏈表 (無哨兵)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