This is a creation in Article, where the information may have evolved or changed.
1. What is a doubly linked list
Reference
And the single-linked list, the elements of the two-way list not only know their downline, but also know their online (more and more like the MLM organization). The small coal car to open, the figure can be seen, each compartment in addition to a point to the back of the car's arrows, there is a pointing to the front of the car's arrows (head, car tail except). The front only points to the rear compartment of the arrow, the rear of the car only pointed to the arrow.
2. Advantages over one-way linked list
1. Insert Delete does not need to move elements, can be inserted in situ delete
2. Bidirectional traversal possible
Inserting data into the middle
Delete Intermediate data
3, bidirectional linked list and go of the corresponding structure
1. Node analysis
Let's break down the compartment first. Each compartment is composed of 4 parts: coal, bodywork, pull-up carriages, ropes, pull-back carriages. The car body is our transportation tool, in the go language we use the structure to raise the dnode to represent, the coal represents the cargo which transports, uses the data variable to express, pulls the front carriage rope and the pull back carriage rope we respectively use the pointer prev and next to indicate. Such a carriage, in the go language is described as follows:
type DNode struct { data Object prev *DNode next *DNode}
2. Doubly linked list
A coal-truck fleet is a doubly linked list. The team has to have the front, car, tail, as the head of the team also need to know how long the team. In the go language, the team with the structure of the dlist, the car head with a variable, the parking space with the tail variable, the length of the fleet is expressed in size, the expression together:
type DList struct { size uint64 head *DNode tail *DNode}
By locating one of the nodes, you can point to the data that you are pointing to by prev or next.
4. Go custom Implementation linked list
1. Initialize Init
bidirectional list initialization, you can understand Chengdawei is ready to buy a team ready to transport coal. The first step, to obtain the approval of the State authorities, with the approval of the Davido can buy the car to transport coal. But when it was approved, brother David's motorcade had nothing, no front, no tail, no car. Go Language code implementation:
Package main//node data structure type Dnode struct {data interface{}prev *dnodenext *dnode}//linked list data structure type dlist struct {size uint64head *dnodetail initialization of *dnode}//list Func initlist () (list *dlist) {list = * (dlist) list.size = 0list.head = Nillist.tail = Nilreturn }//New Data func (Dlist *dlist) Append (Data interface{}) {//Creating a node NewNode: = &dnode{data:data}if (*dlist). GetSize () = = 0 {//Only one node (*dlist). Head = NewNode (*dlist). Tail = newNode//tail-ends are themselves (*newnode). prev = nil//But the direction of the tail is nil ( *newnode). Next = nil} else {//to the tail//new node of the point modification (*newnode). Prev = (*dlist). Tail (*newnode). Next = nil//The point of the tail node before the change (* (*dlist) . tail). Next = NewNode//The next point of the previous tail node points to the new node//update the tail node of the linked list (*dlist). Tail = newnode}//Update the node count (*dlist) of the linked list. size++}/* Insert Data Insertnextparam-ele at the end of the node-the node data to be inserted */func (dlist *dlist) insertnext (ele *dnode, Data interface{}) bool { if ele = = Nil {return false}if Dlist.istail (ele) {///exactly at tail dlist. Append (data)} else {//in the middle Insert//Construct new node NewNode: = new (Dnode) (*newnode). Data = Data (*newnode). prev = EleThe previous node is Ele (*newnode). Next = (*ele). Next//The next node is ele the next node of the original//Ele point to the new node (*ele). Next = newnode// Ele the prev of the next node is re-directed to the new node * ((*newnode) next). Prev = newnode//Update the list count (*dlist). The size++}}/** node before inserting the interface is a similar way: 1. You first create a new node based on the data and set the point to 2. Update the location node to point to Data 3. Update list head, tail, size data Delete node: 1. First get the node that you want to delete point to data (verify Kinsoku) 2. Update the next node of the Prev node to delete nodes (a bit of a mess!!) ) 3. Update the linked list data remember to return the node data to be deleted (otherwise data lost) lookup node: Type matchfun func (data1 interface{}, Data2 interface{}) IntFunc (Dlist *dlist) Search (Data Object, Yourmatch matchfun) *dnode*///Gets the list length Getsizefunc (dlist *dlist) getsize () UInt64 {return (*dlist). siz e}//Gets the head node Getheadfunc (dlist *dlist) gethead () *dnode {return (*dlist). head}//Gets the tail node Gettailfunc (dlist *dlist) GetTail ( ) *dnode {return (*dlist). Tail}
We use Go's container/list library to achieve a more in-depth understanding of the structure of a linked list by implementing its own linked list.
5.Go library container/list for linked list operations
As for the member functions of the library, I will not list them all, and it is very simple to look at the documents in detail.
Directly below the case:
func main() {link := list.New()// 循环插入到头部for i := 0; i <= 10; i++ {link.PushBack(i)}// 遍历链表for p := link.Front(); p != link.Back(); p = p.Next() {fmt.Println("Number", p.Value)}}
6. Performance comparison of Slice and list
1. Create and add a comparison of elements
Package Mainimport ("Container/list" "FMT" "Time") func T1 () {t: = time. Now ()//1 million create add test//slice create slice: = Make ([]int, ten) for I: = 0; i < 1*100000*1000; i++ {slice = append (slice, i)}fmt. Println ("Slice created successfully:", time. Now (). Sub (t). String ())//list creation Add t = time. Now () L: = list. New () for I: = 0; i < 1*100000*1000; i++ {l.pushback (i)}fmt. PRINTLN ("List creation succeeded:", time.) Now (). Sub (t). String ())}func T2 () {SLI: = make ([]int, ten) for I: = 0; i < 1*100000*1000; i++ {SLI = append (SLI, 1)}l: = list. New () for I: = 0; i < 1*100000*1000; i++ {l.pushback (1)}//comparison traversal T: = time. Now () for _, _ = Range SLI {//fmt. Printf ("values[%d]=%d\n", I, Item)}fmt. Println ("Traverse slice speed:" + time.) Now (). Sub (t). String ()) T = time. Now () for e: = L.front (); E! = nil; E = E.next () {//fmt. Println (E.value)}fmt. Println ("Traverse list speed:" + time.) Now (). Sub (t). String ())}func T3 () {SLI: = make ([]int, ten) for I: = 0; i < 1*100000*1000; i++ {SLI = append (SLI, 1)}l: = list. New () for I: = 0; i < 1*100000*1000; i++ {l.pushback (1)}//comparison insert T: = time. Now() Slif: = Sli[:100000*500]slib: = Sli[100000*500:]slif = Append (Slif, ten) Slif = append (Slif, slib ...) Fmt. PRINTLN ("Slice insertion speed" + time.) Now (). Sub (t). String ()) var em *list. Elementlen: = L.len () var i intfor e: = L.front (); E! = nil; E = E.next () {i++if i = = len/2 {em = ebreak}}//ignores the speed at which the intermediate element is found. t = time. Now () EF: = L.pushback (2) l.movebefore (EF, EM) fmt. Println ("list:" + time.) Now (). Sub (t). String ())}
Simple testing, if frequent insertions and deletions are suggested with list, frequent traversal queries are selected slice.
Because container/list is not concurrency-safe, you need to manually add a layer of concurrent packaging yourself.