Go Basis: Introduction and use of list
introduce
The Go built-in container List is a bidirectional linked list (actually a ring). In the package list.
Structure definition
The core structure of a list consists of two lists and elements.
List
The structure of List is as follows:
type List struct {
root Element // sentinel list element, only &root, root.prev, and root.next are used
len int // current list length excluding (this) sentinel element
}
Copy the code
The structure of the List contains two parts:
root
: the type ofElement
The structure of.len
: Used for recordingList
Length (excluding sentinel nodes).
The first node of the List is the sentinel node and does not store any information. The head of the List starts at the next sentinel node.
Element
The structure of elements in the List is as follows:
type Element struct {
list *List
Value interface{}
next, prev *Element
}
Copy the code
As can be seen from the structure of the node, a node in the list contains four elements:
list
: point toList
Pointer to the LIST to which the current node belongsValue
: Used to store the value of an element.next
.prev
: point toElement
Pointer to locate the next node and the previous node.
To simplify the implementation, the internal implementation of the List is 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 ()).
Methods in
The methods are divided into six categories:
- Initialization method
- Basic method
- Insert elements
- Remove elements
- Mobile elements
- Merge list
Initialize the
There are two methods of initialization: Init() and lazyInit().
The Init() method can be used to initialize a linked list, or to clear it.
The lazyInit() method lazily initializes a list with a zero value. From the implementation, we can see that the list is initialized only if the next node of the sentinel is empty.
func (l *List) Init(a) *List {
l.root.next = &l.root
l.root.prev = &l.root
l.len = 0
return l
}
func (l *List) lazyInit(a) {
if l.root.next == nil {
l.Init()
}
}
Copy the code
Basic method
Next()
Returns theThe current nodeNext node of or nil. As you can see from the implementation, whenlist
Is empty orThe next node is the sentinel nodeWhen to return tonil
.Prev()
Returns theThe current nodeOr nil, similar to above.New()
: Returns an initialized list.Len()
: Indicates the number of elements in the linked list. The time complexity is O(1).Front()
: returns the first element of the list. Returns nil when the list is empty.Back()
: returns the last element of the list. Returns nil when the list is empty.
func (e *Element) Next(a) *Element {
ifp := e.next; e.list ! =nil&& p ! = &e.list.root {return p
}
return nil
}
func (e *Element) Prev(a) *Element {
ifp := e.prev; e.list ! =nil&& p ! = &e.list.root {return p
}
return nil
}
func New(a) *List { return new(List).Init() }
func (l *List) Len(a) int { return l.len }
func (l *List) Front(a) *Element {
if l.len= =0 {
return nil
}
return l.root.next
}
func (l *List) Back(a) *Element {
if l.len= =0 {
return nil
}
return l.root.prev
}
Copy the code
Insert elements
insert()
:Underived function. The elementat
Insert an element after the position of, add one to the list length, and return the inserted element.insertValue()
:Underived function. willValue
Packaged inElement
theninsert()
.InsertBefore()
: callinsertValue()
The elementmark
Before inserting. Required elementsmark
The linked list object that belongs to the call and is notnil
.InsertAfter()
And:InsertBefore()
Similarly, in the elementmark
After inserted.PushFront()
: callinsertValue()
Method is inserted in the header of the table. Returns the inserted element.PushBack()
: callinsertValue()
Method is inserted at the end of the table. Returns the inserted element.
func (l *List) insert(e, at *Element) *Element {
e.prev = at
e.next = at.next
e.prev.next = e
e.next.prev = e
e.list = l
l.len++
return e
}
func (l *List) insertValue(v interface{}, at *Element) *Element {
return l.insert(&Element{Value: v}, at)
}
func (l *List) InsertBefore(v interface{}, mark *Element) *Element {
ifmark.list ! = l {return nil
}
return l.insertValue(v, mark.prev)
}
func (l *List) InsertAfter(v interface{}, mark *Element) *Element {
ifmark.list ! = l {return nil
}
return l.insertValue(v, mark)
}
func (l *List) PushFront(v interface{}) *Element {
l.lazyInit()
return l.insertValue(v, &l.root)
}
func (l *List) PushBack(v interface{}) *Element {
l.lazyInit()
return l.insertValue(v, l.root.prev)
}
Copy the code
Remove elements
remove()
:Underived function. Removes elements from the linked liste
If the list length is reduced by one, the deleted element is returned.Remove()
: when elemente
When an element belonging to the invoked list is calledremove()
Function, returnse.Value
.
func (l *List) remove(e *Element) *Element {
e.prev.next = e.next
e.next.prev = e.prev
e.next = nil // Avoid memory leaks
e.prev = nil // Avoid memory leaks
e.list = nil
l.len--
return e
}
func (l *List) Remove(e *Element) interface{} {
if e.list == l {
l.remove(e)
}
return e.Value
}
Copy the code
Mobile elements
move()
:Underived function. The elemente
To the elementat
After, returns the elemente
.MoveToFront()
: the elemente
Move to top of table. Required elementse
The element belonging to the invoked linked list.MoveToBack()
: the elemente
Move to end of table. Required elementse
The element belonging to the invoked linked list.MoveBefore()
: the elemente
To the elementmark
In front of. Required elementse
An element that belongs to and is not an element in the invoked listmark
.MoveAfter()
And:MoveBefore()
Similarly, move behind it.
func (l *List) move(e, at *Element) *Element {
if e == at {
return e
}
e.prev.next = e.next
e.next.prev = e.prev
e.prev = at
e.next = at.next
e.prev.next = e
e.next.prev = e
return e
}
func (l *List) MoveToFront(e *Element) {
ife.list ! = l || l.root.next == e {return
}
l.move(e, &l.root)
}
func (l *List) MoveToBack(e *Element) {
ife.list ! = l || l.root.prev == e {return
}
l.move(e, l.root.prev)
}
func (l *List) MoveBefore(e, mark *Element) {
ife.list ! = l || e == mark || mark.list ! = l {return
}
l.move(e, mark.prev)
}
func (l *List) MoveAfter(e, mark *Element) {
ife.list ! = l || e == mark || mark.list ! = l {return
}
l.move(e, mark)
}
Copy the code
Merge list
PushBackList()
: Put another linked listShallow copyTo the end of the current list. Neither list is required to benil
.PushFronList()
: Put another linked listShallow copyTo the beginning of the current list. Neither list is required to benil
.
func (l *List) PushBackList(other *List) {
l.lazyInit()
for i, e := other.Len(), other.Front(); i > 0; i, e = i- 1, e.Next() {
l.insertValue(e.Value, l.root.prev)
}
}
func (l *List) PushFrontList(other *List) {
l.lazyInit()
for i, e := other.Len(), other.Back(); i > 0; i, e = i- 1, e.Prev() {
l.insertValue(e.Value, &l.root)
}
}
Copy the code
use
Here are three ways to explain the use of list:
- Basic operation
- Simulation of the stack
- Simulation of the queue
Basic operation
The following shows the basic use of linked lists:
l := list.New()
e4 := l.PushBack(4)
e1 := l.PushFront(1)
l.InsertBefore(3, e4)
l.InsertAfter(2, e1)
// Iterate over the output list contents
fore := l.Front(); e ! =nil; e = e.Next() {
fmt.Println(e.Value)
}
Copy the code
The following output is displayed:
1
2
3
4
Copy the code
The stack
We know that the stack has three basic operations: Push(), Pop() and Top(), which Push, Pop, and view the Top of the stack respectively. We can use the list method to simulate the three basic operations: s.pushback (), s.pack ().value, and s.emove (s.pack ()).
stack := list.New()
stack.PushBack(1)
stack.PushBack(2)
stack.PushBack(3)
stack.PushBack(4)
for stack.Len() > 0 {
fmt.Println(stack.Remove(stack.Back()))
}
Copy the code
The output is as follows:
4
3
2
1
Copy the code
The queue
Similarly, we can also use q.pushback () and q.remove (q.front ()) to simulate the queue progress and queue exit operation.
queue := list.New()
queue.PushBack(1)
queue.PushBack(2)
queue.PushBack(3)
queue.PushBack(4)
for l.Len() > 0 {
fmt.Println(l.Remove(l.Front()))
}
Copy the code
The output is as follows:
4
3
2
1
Copy the code