go 语言 链表
鏈表指的是存儲結構是鏈式的。指每一個結點除了本身數據之外,還有一個指針指向了下一個結點的地址。就像火車車廂,車廂本身是數據,車鉤鏈接著下一個車廂。
鏈表有單鏈表,雙鏈表,循環鏈表結構,本節只介紹最簡單的單鏈表
單鏈表定義:
type Student struct {
Name string? ? ? ? ? ? ?//字段,也就是本身的數據,可以有多個字段
Next* Student? ? ? ? ? //指向自己的指針字段
}
例:
type Student struct {Age intName stringNext *People } //定義包含兩個字段一個指針字段的Student的數據類型,為了好理解先定義了一個指向另一個數據類型的指針 type People struct {Age intName string } func testList() {//手動構造兩個節點var s Student //定義Student類型的變量ss.Age = 100 //給變量賦值s.Name = "abc"/*s.Next = &People{Age:100,Name:"efg",}*/ //這個注釋跟下面三行內容一樣的效果。就是給s.Next分配指向People類型的內存地址,并初始化
s.Next = new(People)s.Next.Age = 1000s.Next.Name = "efg"fmt.Printf("list header:%#v\n", s)fmt.Printf("data:%#v\n", *(s.Next)) } //輸出結果 list header:main.Student{Age:100, Name:"abc", Next:(*main.People)(0xc0420023e0)} data:main.People{Age:1000, Name:"efg"}
上面構造了兩個節點,如下圖所示:
下面我們在People類型里再添加一個指針,指向Student類型
type Student struct{Age intName stringNext *People } type People struct {Age intName stringNext *Student //添加一個指向Student類型的指針 } func testList(){var s Student //第一個結點s.Age = 100s.Name = "abc"s.Next = new(People) //第二個結點// s.Next = &People{// Age:100,// Name:"efg",// }s.Next.Age = 1000s.Next.Name = "efg"s.Next.Next = new(Student) //第三個結點s.Next.Next.Age = 100s.Next.Next.Name = "xyz"fmt.Printf("list header:%#v\n", s) //打印第一個結點的信息fmt.Printf("data:%#v\n", *(s.Next)) //打印第二個結點信息fmt.Printf("data:%#v\n", *(s.Next.Next)) //打印第三個節點的信息fmt.Printf("data:%#v\n", s.Next.Next.Next) //打錢第三個節點指針的地址} //輸出結果: list header:main.Student{Age:100, Name:"abc", Next:(*main.People)(0xc0420443a0)} data:main.People{Age:1000, Name:"efg", Next:(*main.Student)(0xc0420443c0)} data:main.Student{Age:100, Name:"xyz", Next:(*main.People)(nil)} data:(*main.People)(nil)現在構造了三個結點,如下圖所示:
上面構造節點的方法慢,且邏輯復雜,而且指針是指向了另一種數據結構類型的,需要對它進行抽象。也就是說需要利用模板來生成結點。而且生成一個指向自己的指針,來構造鏈表。
上面的方法是手動構造了三個節點的鏈表,下面利用函數來動態的生成結點。
type Teacher struct{ //定義鏈表的存儲結構Name stringAge intNext *Teacher } func createInHeader(h *Teacher, name string, age int) (*Teacher) { //這個函數的主要作用是生成一個新的結點,并且把頭部結點的指針的值賦值給新的結點,并且返回這個這個結點的內存地址,再把這個新的結點的內存地址賦值給頭部結點p := &Teacher{} //相當于 var p *Teacher p = &Teacher{},申明變量,并分配一個內存地址p.Age = age //字段屬性賦值p.Name = namep.Next = h //把頭結點指針的值賦值給新結點return p //返回新節點的地址 } func printList(h *Teacher){for h != nil{fmt.Printf("Name:%v Age:%v\n",h.Name,h.Age)h = h.Next //后移一個節點} } func testCreateInHeader() {var header *Teacher //定義一個指針變量header = createInHeader(header, "a", 18) //header指向第一個生成的結點header = createInHeader(header, "b", 19) //header指向第二個生成的結點header = createInHeader(header, "c", 20) //header指向第三個生成的結點printList(header) } //輸出結果 Name:c Age:20 Name:b Age:19 Name:a Age:18上面動態生成三個結點,每次相當于前插,就是header指針變量每次都指向最新生成的那個結點。上面構造的三個節點的鏈式存儲結構為:
?
?下面演示從最后插入:
type Teacher struct{Name stringAge intNext *Teacher } func printList(h *Teacher){for h != nil{fmt.Printf("Name:%v Age:%v\n",h.Name,h.Age)h = h.Next} } func createInTail(tail *Teacher, name string, age int) (*Teacher) { //生成新的結點,并把新生成的節點的地址返回給尾指針變量。尾指針變量永遠指向最后一個結點。p := &Teacher{}p.Age = agep.Name = nameif tail == nil { //如果一開始沒有節點,則直接返回新生成的結點的地址給尾指針變量return p}tail.Next = p //假設已經有了一個節點,那么tail != nil,則一行表示把原尾結點的指針指向新生成的結點return p //返回新生成結點的地址 } func testCreateInTail() {var header *Teachervar tail *Teachertail = createInTail(tail, "a", 18)if header == nil {header = tail //生成第一個節點時,header也指向了第一個節點}tail = createInTail(tail, "b", 19)//尾指針永遠指向新生成的結點tail = createInTail(tail, "c", 20)printList(header) }//輸出結果是:
Name:a Age:18
Name:b Age:19
Name:c Age:20
上面構造的節點的鏈式存儲結構為:
?
轉載于:https://www.cnblogs.com/wanghaijun999/p/8136253.html
總結
- 上一篇: .NET Core容器化@Docker
- 下一篇: ionic3 动态设置tabs页面底部导