01.4鏈錶

鏈錶(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)
    }
    
鏈接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值