Go 語言的雙向鏈表、list 操作和雙向循環鏈表- 這些誰認識?

雙向鏈表

1)雙向鏈表的結構

雙向鏈表結構中元素在內存中不是緊鄰空間,而是每個元素中存放上一個元素和後一個元素的地址

雙向鏈表的優點

雙向鏈表的缺點

2)雙向鏈表容器 List

在 Go 語言標準庫的 container/list 包提供了雙向鏈表 List

List 結構體定義如下

// 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 used
    len  int     // current list length excluding (this) sentinel element
}

其中 Element 結構體定義如下

// Element is an element of a linked 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

  1. 直接使用 container/list 包下的 New() 新建一個空的 List

添加,遍歷,取首尾,取中間元素

package main

import (
    "container/list"
    "fmt"
)

func main() {
    //實例化
    mylist := list.New()
    fmt.Println(mylist)

    //添加
    mylist.PushFront("a")                        //["a"]
    mylist.PushBack("b")                         //["a","b"]
    mylist.PushBack("c")                         //["a","b","c"]
    //在最後一個元素的前面添加
    mylist.InsertBefore("d",mylist.Back())       //["a","b","d","c"]
    mylist.InsertAfter("e",mylist.Front())       //["a","e","b","d","c"]

    //遍歷
    for e := mylist.Front(); e != nil; e = e.Next(){
        fmt.Print(e.Value, " ")     //a e b d c
    }
    fmt.Println("")

    //取首尾
    fmt.Println(mylist.Front().Value)     //a
    fmt.Println(mylist.Back().Value)      //c

    //取中間的元素,通過不斷的Next()
    n := 3
    var curr *list.Element
    if n > 0 && n <= mylist.Len(){
        if n == 1 {
            curr = mylist.Front()
        }else if n == mylist.Len(){
            curr = mylist.Back()
        }else {
            curr = mylist.Front()
            for i := 1; i < n; i++{
                curr = curr.Next()
            }
        }
    }else {
        fmt.Println("n的數值不對")
    }
    fmt.Println(curr.Value)        //b
}

2)移動元素 

package main

import (
    "container/list"
    "fmt"
)

func main() {
    //實例化
    mylist := list.New()
    fmt.Println(mylist)

    //添加
    mylist.PushFront("a")                        //["a"]
    mylist.PushBack("b")                         //["a","b"]
    mylist.PushBack("c")                         //["a","b","c"]
    //在最後一個元素的前面添加
    mylist.InsertBefore("d",mylist.Back())       //["a","b","d","c"]
    mylist.InsertAfter("e",mylist.Front())       //["a","e","b","d","c"]

    //移動,把第一個元素一道最後一個元素的前面
    mylist.MoveBefore(mylist.Front(),mylist.Back())
    //mylist.MoveAfter(mylist.Back(),mylist.Front())

    //把最後一個元素移動到最前面
    //mylist.MoveToFront(mylist.Back())
    //把第一個元素移動到最後面
    //mylist.MoveToBack(mylist.Front())

    for e := mylist.Front(); e != nil; e = e.Next(){
        fmt.Print(e.Value, " ")     //e b d a c
    }
}

3)刪除

mylist.Remove(mylist.Front())

雙向循環列表

1)循環鏈表特點是沒有節點的指針域爲 nil,通過任何一個元素都可以找到其它元素。環形鏈表結構如下

雙向循環鏈表和雙向鏈表區別

2)在 container/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 *Ring
    Value      interface{} // for use by client; untouched by this library
}

3)創建和查看  

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    //r代表整個循環鏈表,又代表第一個元素
    r := ring.New(5)
    r.Value = 0
    r.Next().Value = 1
    r.Next().Next().Value = 2
    //r.Next().Next().Next().Value = 3
    //r.Next().Next().Next().Next().Value = 4
    r.Prev().Value = 4
    r.Prev().Prev().Value = 3
    //查看元素內容
    //循環鏈表有幾個元素,func就執行幾次,i當前執行元素的內容
    r.Do(func(i interface{}) {
        fmt.Print(i, " ")      //0 1 2 3 4
    })
    fmt.Println("")
    //取中間元素,用移動
    fmt.Println(r.Move(3).Value)   //3


}

4)增加

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    //r代表整個循環鏈表,又代表第一個元素
    r := ring.New(5)
    r.Value = 0
    r.Next().Value = 1
    r.Next().Next().Value = 2
    //r.Next().Next().Next().Value = 3
    //r.Next().Next().Next().Next().Value = 4
    r.Prev().Value = 4
    r.Prev().Prev().Value = 3

    //增加
    r1 := ring.New(2)
    r1.Value = 5
    r1.Next().Value = 6
    r.Link(r1)

    r.Do(func(i interface{}) {
        fmt.Print(i, " ")    //0 5 6 1 2 3 4
    })
}

5)刪除

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    //r代表整個循環鏈表,又代表第一個元素
    r := ring.New(5)
    r.Value = 0
    r.Next().Value = 1
    r.Next().Next().Value = 2
    //r.Next().Next().Next().Value = 3
    //r.Next().Next().Next().Next().Value = 4
    r.Prev().Value = 4
    r.Prev().Prev().Value = 3

    //刪除
    r.Unlink(1)

    r.Do(func(i interface{}) {
        fmt.Print(i, " ")    //0 2 3 4
    })
}

刪除後面兩個

//刪除
r.Unlink(2)

r.Do(func(i interface{}) {
    fmt.Print(i, " ")    //0 3 4
})

r.Next() 刪除

//刪除
r.Next().Unlink(2)

r.Do(func(i interface{}) {
    fmt.Print(i, " ")    //0 1 4
})qu

超出範圍,取 5 的餘數

//刪除
r.Unlink(6)

r.Do(func(i interface{}) {
    fmt.Print(i, " ")    //0 2 3 4
})

文章首發:https://www.cnblogs.com/derek1184405959/p/11298618.html

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/77cIKTJA_OxqY-7WSv2K_w