鏈錶(linked list)
-
基本介紹
鏈錶由一系列結點組成,結點可以在運行時動態生成。每個節點包括兩個部分:一個是儲存數據元素的數據域,另一個是儲存下一個結點地址的指針域。
-
單向鏈錶
單鏈表一般應設頭指針指向開始節點,終端結點的指針域為空,即NULL。單鏈表的建立有頭插法和尾插法兩種。
-
代碼案例
type Node struct { no int//序號 name string//數據 next *Node//下個結點 } //插入在最後 func Insert(head,newNode *Node) { for { //判斷是否為最後一個結點 if head.next == nil { break } //不斷指向下一個結點 head = head.next } head.next = newNode } //按序號插入 func InsertBySort(head,newNode *Node) { for { //判斷是否為最後一個結點||判斷當前頭結點的下一個結點與新結點的序號大小 if head.next == nil || head.next.no > newNode.no { //新結點指向頭結點的下一個結點 newNode.next = head.next //當前頭結點改為指向新結點 head.next = newNode break } //判斷結點的序號是否重複 if head.next.no == newNode.no { fmt.Println("序號重複") break } //不斷指向下一個結點 head = head.next } } func ShowNode(head *Node){ if head.next == nil { fmt.Println("是空的") return } for{ fmt.Printf("%d,%s",head.next.no,head.next.name) fmt.Println() head = head.next if head.next == nil { break } } } func DelNode(head *Node,id int) { for { if head.next == nil { fmt.Println("沒有找到需要刪除的結點") break } if head.next.no == id { head.next = head.next.next fmt.Println("成功刪除結點") break } head = head.next } } func main(){ head :=&Node{} no1 := &Node{ no:1, name:"宋江", } no2 := &Node{ no:2, name:"盧俊義", } no3 := &Node{ no:3, name:"豹子頭", } no4 := &Node{ no:3, name:"吳用", } InsertBySort(head,no4) InsertBySort(head,no1) InsertBySort(head,no3) InsertBySort(head,no2) ShowNode(head) DelNode(head,3) ShowNode(head) }
-
雙向鏈錶
它的每個數據結點中都有兩個指針,分別指向直接後繼和直接前驅。
-
代碼案例
type Node struct { no int//序號 name string//數據 pre *Node//上個結點 next *Node//下個結點 } //插入在最後 func Insert(head,newNode *Node) { for { //判斷是否為最後一個結點 if head.next == nil { break } //不斷指向下一個結點 head = head.next } head.next = newNode newNode.pre = head } //按序號插入 func InsertBySort(head,newNode *Node) { for { //判斷是否為最後一個結點||判斷當前頭結點的下一個結點與新結點的序號大小 if head.next == nil || head.next.no > newNode.no { //新結點指向頭結點的下一個結點 newNode.next = head.next //新結點指向頭結點 newNode.pre = head //如果頭結點之後不是空結點就指向新結點 if head.next != nil { head.next.pre = newNode } //當前頭結點改為指向新結點 head.next = newNode break } //判斷結點的序號是否重複 if head.next.no == newNode.no { fmt.Println("序號重複") break } //不斷指向下一個結點 head = head.next } } //不同於單向鏈錶,雙向鏈錶亦可以從尾結點遍歷 func ShowNode(head *Node){ if head.next == nil { fmt.Println("是空的") return } //定位到雙向鏈錶的最後 for { if head.next == nil { break } head = head.next } for{ fmt.Printf("%d,%s",head.no,head.name) fmt.Println() head = head.pre if head.pre == nil { break } } } func DelNode(head *Node,id int) { for { if head.next == nil { fmt.Println("沒有找到需要刪除的結點") break } if head.next.no == id { head.next = head.next.next if head.next != nil { head.next.pre = head } fmt.Println("成功刪除結點") break } head = head.next } } func main(){ head :=&Node{} no1 := &Node{ no:1, name:"宋江", } no2 := &Node{ no:2, name:"盧俊義", } no3 := &Node{ no:3, name:"豹子頭", } no4 := &Node{ no:3, name:"吳用", } InsertBySort(head,no4) InsertBySort(head,no1) InsertBySort(head,no3) InsertBySort(head,no2) ShowNode(head) DelNode(head,3) ShowNode(head) }
-
單向環形鏈錶
約瑟夫问题:N個人圍成一圈,從第一個開始報數,第M個將被殺掉,最後剩下一個,其餘人都將被殺掉。
-
代碼案例(有序、無序環形鏈錶)
type Node struct { no int//序號 name string//數據 next *Node//下個結點 } //插入在最後 func Insert(head,newNode *Node) { help := head //判斷是否為第一個結點,第一個結點之後將構成環,不再出現nil if head.next == nil { head.no = newNode.no head.name = newNode.name //請注意這裡不能使用下列語句代替 //head = newNode //這樣會將head的副本指針指向到newNode結構體 //下一次head的新副本指針仍然指向head,head.next將一直是nil head.next = head//構成一個環形 fmt.Println(newNode.name,"加入環形鏈錶") return } //找到最後一個結點 for { if head.next == help { newNode.next = head.next head.next = newNode fmt.Println(newNode.name,"加入環形鏈錶") break } head = head.next } } //按序號插入 func InsertBySort(head,newNode *Node) { help := head //判斷是否為第一個結點,第一個結點之後將構成環,不再出現nil if head.next == nil { head.no = newNode.no head.name = newNode.name head.next = head//構成一個環形 fmt.Println(newNode.name,"加入環形鏈錶") return } for { //是否需要替換頭結點,本質上只是交換結點信息,並不是替換結點 if head.no > newNode.no { middle := &Node{ no:head.no, name:head.name, } head.no,head.name = newNode.no,newNode.name newNode.no,newNode.name = middle.no,middle.name } //判斷是否為最後一個結點,判斷當前頭結點與新結點的序號大小 if head.next == help || head.next.no > newNode.no { //新結點指向頭結點的下一個結點 newNode.next = head.next //當前頭結點改為指向新結點 head.next = newNode fmt.Println(newNode.name,"加入環形鏈錶") break } //判斷結點的序號是否重複 if head.next.no == newNode.no { fmt.Println("序號重複") break } //不斷指向下一個結點 head = head.next } } func ShowNode(head *Node){ help := head if head.next == nil { fmt.Println("是空的") return } for{ //第一次就打印頭結點 fmt.Printf("%d,%s",head.no,head.name) fmt.Println() if head.next == help { break } head = head.next } } func DelNode(head *Node,id int) (*Node) { //移動節點,用於比較結點所用 mobile := head //移動節點的前結點,用於比較結點所用 premobile := head //先判斷是否為空鏈錶 if head.next == nil { fmt.Println("空鏈錶不可刪除") return head } //判斷是否為單結點 if head.next == head { if head.no == id { head.next = nil fmt.Println("已刪除") } fmt.Println("未找到需要刪除的結點") return head } //定位到最後一個結點 for { premobile = premobile.next if premobile.next == head { break } } for { //找了一個圈 if mobile.next == head { //如果尾結點是要刪除的結點 if mobile.no == id { premobile.next = head fmt.Println("已刪除結點",mobile.name) break } fmt.Println("未找到需要刪除的結點") break } if mobile.no == id { //如果要刪除頭結點,要替換為下一個結點 if mobile == head { head = mobile.next } premobile.next = mobile.next fmt.Println("成功刪除結點",mobile.name) break } mobile = mobile.next premobile = premobile.next } return head } func main(){ head :=&Node{} no1 := &Node{ no:1, name:"宋江", } no2 := &Node{ no:2, name:"盧俊義", } no3 := &Node{ no:3, name:"豹子頭", } no4 := &Node{ no:3, name:"吳用", } InsertBySort(head,no4) InsertBySort(head,no1) InsertBySort(head,no3) InsertBySort(head,no2) ShowNode(head) //刪除需要定義一個新的頭結點,否則在另一個函數刪除頭結點之後 // show函數仍然引用著這個老的結點,這裡引用實質是地址的複製 head = DelNode(head,1) ShowNode(head) }
-
約瑟夫問題
type Node struct { no int//序號 next *Node//下個結點 } //插入num個節點,並返回第一個結點 func Add(num int) *Node { //輔助結點 first,current := &Node{},&Node{} //數量大於0 if num < 1 { fmt.Println("num的值不合格") return first } //生成各個結點 for i := 1;i<= num;i++ { node := &Node{ no:i, } //從第一個結點開始構成一個循環鏈錶 if i == 1 { first,current = node,node first.next = first }else { current.next = node current = node current.next = first } } return first } func ShowNode(first *Node){ head := first if first.next == nil { fmt.Println("是空的") return } for{ //第一次就打印頭結點 fmt.Printf("%d",head.no) fmt.Println() if head.next == first { break } head = head.next } } func PlayGame(head *Node,start,count int) { //輔助指針 tail := head //先判斷是否為空鏈錶 if head.next == nil { fmt.Println("空鏈錶不可刪除") return } for { if tail.next == head { break } tail = tail.next } //以start為准,調整head與tail for i := 1;i<start;i++ { head = head.next tail = tail.next } for { //計數,由於start是第一個數,所以需要再輸count-1次 for i := 1;i<count;i++ { head = head.next tail = tail.next } fmt.Println("已刪除編號",head.no) head = head.next tail.next = head if tail == head { break } } fmt.Println("倖存者是",head.no) } func main(){ first := Add(30) ShowNode(first) PlayGame(first,20,19) }