Container/ring-golang-標準庫閱讀

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

相關文章
相關標籤/搜索