Go 標準庫閱讀:Container-ring

【導讀】Go 標準庫 Container 中實現了一些數據結構,可以方便直接地利用這些庫實現邏輯。本文介紹了 ring 的實現。

相較於 List , ring 因爲不需要哨兵快速找到頭尾,所以只有一個 struct ring (環)

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 方法,支持正向移動和反方向移動 (向左或向右移動)

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
}

也可以給加入環節點或者刪除環節點 (類似於)

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 的前驅節點進行鏈接,組成一個新的雙向鏈表實現的環

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() 方法,允許使用閉包函數遍歷 整個 Ring

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)
  }
 }
}【導讀】阿斯頓發

ring
type Ring struct {
    // 前後節點
 next, prev *Ring
 Value      interface{}
}

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
}

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
}

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
}

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
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 節點連接起來
     // 則中間的這些節點相當於從環中被排除掉
    )
}

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)
  }
 }
}

轉自:juejin.cn/post/6844903865821691918

Go 開發大全

參與維護一個非常全面的 Go 開源技術資源庫。日常分享 Go, 雲原生、k8s、Docker 和微服務方面的技術文章和行業動態。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/69gmtfu6YalZT566lHXifA