這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Go container包
container/list-雙向鏈表-List
基本的資料結構
type Element struct {// Next and previous pointers in the doubly-linked list of elements.// To simplify the implementation, internally a list l is implemented// as a ring, such that &l.root is both the next element of the last// list element (l.Back()) and the previous element of the first list// element (l.Front()).next, prev *Element// The list to which this element belongs.list *List// The value stored with this element.Value interface{}}// List represents a doubly linked list.// The zero value for List is an empty list ready to use.type List struct {root Element // sentinel list element, only &root, root.prev, and root.next are usedlen int // current list length excluding (this) sentinel element}
雙向鏈表是鏈表的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。一般我們都構造雙向迴圈鏈表。
舉例說明,
package mainimport ("container/list""fmt")func print(l *list.List) {for e := l.Front(); e != nil; e = e.Next() {fmt.Println(e.Value)}}func main() {l := list.New()l.PushBack(1) //尾插l.PushBack(2)print(l)fmt.Println("=========")l.PushFront(0) //頭插print(l)fmt.Println("=========")for e := l.Front(); e != nil; e = e.Next() {if e.Value == 1 {l.InsertAfter(1.1, e)}if e.Value == 2 {l.InsertBefore(1.2, e)}}print(l)fmt.Println("=========")fmt.Println(l.Front().Value) //返回鏈表的第一個元素fmt.Println("=========")fmt.Println(l.Back().Value) //返回鏈表的最後一個元素fmt.Println("=========")l.MoveToBack(l.Front())print(l)fmt.Println("=========")for e := l.Back(); e != nil; e = e.Prev() {fmt.Println(e.Value)}}
container/heap-堆-Heap
堆資料結構具體請看:
https://my.oschina.net/xinxingegeya/blog/703801
https://my.oschina.net/xinxingegeya/blog/705409
在Golang中,定義了一組方法來描述堆的操作。如下介面描述,
// Any type that implements heap.Interface may be used as a// min-heap with the following invariants (established after// Init has been called or if the data is empty or sorted):////!h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()//// Note that Push and Pop in this interface are for package heap's// implementation to call. To add and remove things from the heap,// use heap.Push and heap.Pop.type Interface interface {sort.InterfacePush(x interface{}) // add x as element Len()Pop() interface{} // remove and return element Len() - 1.}
heap.Interface 組合了 sort.Interface 介面,
// A type, typically a collection, that satisfies sort.Interface can be// sorted by the routines in this package. The methods require that the// elements of the collection be enumerated by an integer index.type Interface interface {// Len is the number of elements in the collection.Len() int// Less reports whether the element with// index i should sort before the element with index j.Less(i, j int) bool// Swap swaps the elements with indexes i and j.Swap(i, j int)}
也就是說只要一個類型實現了這五個方法,便定義了一個堆。如下所示,
package mainimport ("container/heap""fmt")type Student struct {name stringscore int}type StudentHeap []Studentfunc (h StudentHeap) Len() int { return len(h) }func (h StudentHeap) Less(i, j int) bool {return h[i].score < h[j].score //最小堆//return stu[i].score > stu[j].score //最大堆}func (h StudentHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }func (h *StudentHeap) Push(x interface{}) {// Push and Pop use pointer receivers because they modify the slice's length,// not just its contents.*h = append(*h, x.(Student))}func (h *StudentHeap) Pop() interface{} {old := *hn := len(old)x := old[n-1]*h = old[0: n-1]return x}func main() {h := &StudentHeap{{name: "xiaoming", score: 82},{name: "xiaozhang", score: 88},{name: "laowang", score: 85}}// 初始化一個堆。一個堆在使用任何堆操作之前應先初始化。// Init函數對於堆的約束性是等冪的(多次執行無意義),並可能在任何時候堆的約束性被破壞時被調用。// 本函數複雜度為O(n),其中n等於h.Len()。heap.Init(h)//向堆h中插入元素x,並保持堆的約束性。複雜度O(log(n)),其中n等於h.Len()。heap.Push(h, Student{name: "xiaoli", score: 66})for _, ele := range *h {fmt.Printf("student name %s,score %d\n", ele.name, ele.score)}for i, ele := range *h {if ele.name == "xiaozhang" {(*h)[i].score = 60// 在修改第i個元素後,調用本函數修複堆,比刪除第i個元素後插入新元素更有效率。// 複雜度O(log(n)),其中n等於h.Len()。heap.Fix(h, i)}}fmt.Println("==========")for _, ele := range *h {fmt.Printf("student name %s,score %d\n", ele.name, ele.score)}fmt.Println("==========")for h.Len() > 0 {// 刪除並返回堆h中的最小元素(取決於Less函數,最大堆或最小堆)(不影響堆de約束性)// 複雜度O(log(n)),其中n等於h.Len()。該函數等價於Remove(h, 0)item := heap.Pop(h).(Student)fmt.Printf("student name %s,score %d\n", item.name, item.score)}}
列印結果,
student name xiaoli,score 66student name xiaoming,score 82student name laowang,score 85student name xiaozhang,score 88==========student name xiaozhang,score 60student name xiaoli,score 66student name laowang,score 85student name xiaoming,score 82==========student name xiaozhang,score 60student name xiaoli,score 66student name xiaoming,score 82student name laowang,score 85Process finished with exit code 0
container/ring-環-Ring
Ring的資料結構,
// A Ring is an element of a circular list, or ring.// Rings do not have a beginning or end; a pointer to any ring element// serves as reference to the entire ring. Empty rings are represented// as nil Ring pointers. The zero value for a Ring is a one-element// ring with a nil Value.//type Ring struct {next, prev *RingValue interface{} // for use by client; untouched by this library}
像是雙向迴圈鏈表,雙向鏈表和雙向迴圈鏈表的結構,
如下程式碼範例,
package mainimport ("container/ring""fmt")func main() {ring1 := ring.New(3)for i := 1; i <= 3; i++ {ring1.Value = iring1 = ring1.Next()}ring2 := ring.New(3)for i := 4; i <= 6; i++ {ring2.Value = iring2 = ring2.Next()}r := ring1.Link(ring2)fmt.Printf("ring length = %d\n", r.Len())r.Do(func(p interface{}) {fmt.Print(p.(int))fmt.Print(",")})fmt.Println()fmt.Printf("current ring is %v\n", r.Value)fmt.Printf("next ring is %v\n", r.Next().Value)fmt.Printf("prev ring is %v\n", r.Prev().Value)// ring 的遍曆for p := r.Next(); p != r; p = p.Next() {fmt.Print(p.Value.(int))fmt.Print(",")}}
=======END=======