The container package implements three complex data structures: heaps, lists, loops (heap, list, and ring). When we need to use these data structures can be used directly without having to implement the correlation algorithm.
1. Heap
The data structure used by the heap is the smallest binary tree, that is, the root node is smaller than all the values of the left and right subtrees. The go heap package just implements an interface and looks at its definition:
type Interface interface { sort.Interface Push(x interface{}) // add x as element Len() Pop() interface{} // remove and return element Len() - 1.}
As you can see, this heap combines the sort package sort.Interface , and in retrospect sort.Interface , it needs to implement three methods
Len() intLess(i, j int) boolSwap(i, j int)
Add two methods to the heap interface definition
Push(x interface{})Pop() interface{}
That means you define a heap, you have to implement five methods, just take the example in Package doc as an example:
type IntHeap []intfunc (h IntHeap) Len() int { return len(h) }func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }func (h *IntHeap) Push(x interface{}) { *h = append(*h, x.(int))}func (h *IntHeap) Pop() interface{} { old := *h n := len(old) x := old[n-1] *h = old[0 : n-1] return x}
Then intheap implements the heap structure, and we can use the heap method to manipulate it:
h := &IntHeap{2, 1, 5}heap.Init(h)heap.Push(h, 3)heap.Pop(h)
Specifically, the internal implementation is to use the smallest heap, the index sort starts from the root node, and then the left subtree, the right subtree in the order of the tree. Internally implemented down and up expressed separately to an element in the heap, the minimum heap is guaranteed and the minimum heap is guaranteed upward.
When inserting an element into the heap, this element is inserted into the last node of the right-most subtree, and then the up-up is called up to ensure the minimum heap.
When you want to roll out an element from the heap, first the element is redeemed with the last node in the right subtree, then the last node pops up, then the root is called down, and the minimum heap is guaranteed down.
Linked list
A linked list is an prev next array with pointers. It maintains two type , (note, here is not interface)
type Element struct { next, prev *Element // 上一个元素和下一个元素 list *List // 元素所在链表 Value interface{} // 元素}type List struct { root Element // 链表的根元素 len int // 链表的长度}
The basic use is to create a list first, then insert a value into the list, the list creates an element inside, and internally sets the element's Next,prev and so on. You can see the following example:
// This example demonstrates an integer heap built using the heap interface.package mainimport ( "container/list" "fmt")func main() { list := list.New() list.PushBack(1) list.PushBack(2) fmt.Printf("len: %v\n", list.Len()); fmt.Printf("first: %#v\n", list.Front()); fmt.Printf("second: %#v\n", list.Front().Next());}
output:len: 2first: &list.Element{next:(*list.Element)(0x2081be1b0), prev:(*list.Element)(0x2081be150), list:(*list.List)(0x2081be150), Value:1}second: &list.Element{next:(*list.Element)(0x2081be150), prev:(*list.Element)(0x2081be180), list:(*list.List)(0x2081be150), Value:2}
The list corresponds to the following methods:
Type Element func (e *element) Next () *element func (e *element) Prev () *elementtype List func New () *list Fun C (L *list) back () *element//Last element func (l *list) Front () *element//First element func (L *list) Init () *list//List Initialize func (l *list) InsertAfter (v interface{}, Mark *element) *element//insert Func after an element (L *list) insertbefore (v inte rface{}, Mark *element) *element//Insert Func (L *list) Len () int//In the list length func (l *list) MoveAfter (E, Mark *el) before an element ement)//move e element to mark after Func (l *list) MoveBefore (E, Mark *element)//move e element to mark before Func (l *list) movetoback (E * Element)//Move the E element to the end of the queue func (L *list) Movetofront (e *element)//Move the E element to the head of the queue func (L *list) pushback (v interface{} ) *element//At the end of the queue Insert element func (L *list) pushbacklist (other *list)//At the end of the queue insert the new queue func (L *list) Pushfront (v Interf ace{}) *element//Insert element in Queue header func (l *list) pushfrontlist (other *list)//In queue header Insert new queue func (L *list) Remove (e *ele ment) interface{}//Delete aAn element
Ring
The structure of the ring is a bit special, the tail of the ring is the head, so each element can actually represent its own ring. It doesn't need to keep list and element two structures like list, just keep a structure on the line.
type Ring struct { next, prev *Ring Value interface{}}
When we initialize the ring, we need to define the size of the ring, and then assign values to each element of the ring. The ring also provides a Do way to facilitate the loop, performing a function on each element. Look at the following example:
// This example demonstrates an integer heap built using the heap interface.package mainimport ( "container/ring" "fmt")func main() { ring := ring.New(3) for i := 1; i <= 3; i++ { ring.Value = i ring = ring.Next() } // 计算1+2+3 s := 0 ring.Do(func(p interface{}){ s += p.(int) }) fmt.Println("sum is", s)}
output:sum is 6
The ring provides methods that have
type ring func New (n int) *ring//Initialize ring func (R *ring) do (f func (interface{}))//cyclic ring operation Func (R *ring) Len () int//Ring length func (r *ring) Link (s *ring) *ring//Connect two ring func (R *ring) Move (n int) *ring//pointer from The current element begins to move backwards or forwards (n can be negative) func (R *ring) next () *ring//The next element of the current element func (R *ring) Prev () *ring//The last element of the current element func (r *ring) Unlink (n int) *ring//start with the current element, delete n elements