從源碼分析:Go中的環ring

引言

在之前的文章Go中的雙向鏈表list的使用從源碼分析:Go中的雙線鏈表list,我們一起看了Go中的容器list的使用與其源碼的實現原理,這一次,我們來看一下另一個容器,也就是標題中所述的ring,Go中的環形鏈表,與container/list一樣,ring同樣位於包conatainer中。

數據結構

還是老規矩,一開始先看一下ring中所使用的數據結構。其實ring中使用的結構比較少,只有一個叫做Ring的結構體。

// 一個Ring是一個環形鏈表的元素,對於環而言,並不存在起始點或者終止點。
// 指向環中任一元素的指針都用作整個環的引用
// nil環指針指向空的環,對於環來說0值是一個只有一個nil元素的一個元素的環
type Ring struct {
    // 分別指向下一個元素與上一個元素
    next, prev *Ring
    // 該元素內實際存儲的數據
	Value      interface{} // for use by client; untouched by this library
}

創建實例與初始化的方法

接下來是如何創建一個ring的實例與環的初始化方法

// 創建新的長度爲n的ring實例的方法
func New(n int) *Ring {
    // 如果輸入的n爲小於零的負數,則直接返回nil
	if n <= 0 {
		return nil
    }
    // 首先創建一個Ring的實例r,並將指針p指向r
	r := new(Ring)
    p := r
    // 從1到n - 1循環,創建n - 1個Ring的實例,並依次將其接起來
	for i := 1; i < n; i++ {
        // 這裏,創建了一個Ring的實例,創建時將新的實例的prev指向當前節點(等號後部分),並將當前節點p的next指針指向了新創建的節點(等號前的部分)
        p.next = &Ring{prev: p}
        // 將指針向後移
		p = p.next
    }
    // 在創建完n個節點後,此時仍然是一個單向的鏈表,因此之後需要將該鏈表的首尾連接起來
	p.next = r
	r.prev = p
	return r
}

// 環的初始化方法,將初始點的前一節點與後一節點的指針都指向初始節點,之後將初始節點的指針返回
func (r *Ring) init() *Ring {
	r.next = r
	r.prev = r
	return r
}

環的遍歷方式

list中的每個元素一樣,ring中的每個元素也是使用Next()Prev()方法來進行向後與向前遍歷。

// Next()方法返回環中的下一個元素,注意:r不能爲空
func (r *Ring) Next() *Ring {
	if r.next == nil {
		return r.init()
	}
	return r.next
}

// Prev()方法返回環中的前一個元素,注意:r不能爲空
func (r *Ring) Prev() *Ring {
	if r.next == nil {
		return r.init()
	}
	return r.prev
}

移動元素指針

// 在環中移動n個元素,若n爲負數,則向後移動,若n大於等於0,則向前移動,若n比r的長度更大,則移動n % r.Len()個元素。
// 之後返回環元素,注意r不能爲空。
//
func (r *Ring) Move(n int) *Ring {
    // 如果r的下一個節點爲nil的話,說明此時環的結構是已經被破壞的,因此對其進行初始化。
	if r.next == nil {
		return r.init()
    }
    // 判斷n的正負,來確定是向前移動還是向後移動。
	switch {
	case n < 0:
		for ; n < 0; n++ {
			r = r.prev
		}
	case n > 0:
		for ; n > 0; n-- {
			r = r.next
		}
	}
	return r
}

連接

//將環r與環s連接起來,使得r.Next()成爲s並且返回r.Next()的初始值,r必須不能爲空。
// 日過r和s指向同一個環,則對其的連接會移除r和s之間的元素。被移除的元素會構成一個子環,並且結果是一個指向這個子環的引用(如果沒有元素被移除,則結果仍然是r.Next()的初始值,而不是nil)
// 如果r和s指向不同的環,將它們連接會創建一個單獨的環,環中s的元素會插入在r之後。結果會指向插入之後s的最後一個元素之後。
func (r *Ring) Link(s *Ring) *Ring {
    // 將r的下一個元素取出
    n := r.Next()
    // 判斷s是否爲nil,如果是nil則直接返回n
	if s != nil {
        // 將s的前一元素取出s
        p := s.Prev()
		// 將r的後一節點置爲s,同時將r的原先的後一節點的前一節點置爲s原先的前一節點。
		r.next = s
		s.prev = r
		n.prev = p
		p.next = n
	}
	return n
}

// 將r之後的n個元素刪除,返回被刪除的子環,r不能爲空
func (r *Ring) Unlink(n int) *Ring {
	if n <= 0 {
		return nil
	}
	return r.Link(r.Move(n + 1))
}

其它

// 計算環的長度,它按與元素數量成比例的時間執行。
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 calls function f on each element of the ring, in forward order.
// The behavior of Do is undefined if f changes *r.
// 傳入一個函數,對環中的所有元素都執行一遍這個函數,執行的順序是正向的順序。
// 如果函數f改變* r,那麼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)
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章