3rdworld

导航

链表学习-双向链表go实现 [3]

go实现双向链表



示例代码

  1. 定义一个存储英雄信息的结构HeroNode,其中next为下一个英雄节点的内存地址,last为最后一个英雄节点的内存地址(append时不用遍历)

  2. 初始化head节点,和四个英雄节点

  3. InsertHeroNodeEnd 末尾插入;InsertHeroNodeOrder比对Tire的大小,找到临界面值

  4. ListHeroNode输出节点信息(只需要传入head即可)

    package main
    
    import (
    	"fmt"
    )
    
    type HeroNode struct {
    	tier     int8      // 英雄所属层级
    	next     *HeroNode //指向下一个节点
    	last     *HeroNode // append操作用
    	pre      *HeroNode //指向前一个节点
    	name     string // 名称
    	nickname string // 别名
    	mantra   string // 英雄的台词
    }
    
    // 2.按照tier 从小到大排序
    func InsertHeroNodeOrder(head *HeroNode, newHero *HeroNode) {
    	currentHeroNode := head
    	for { // 让插入节点的tier currentHeroNode的下一个节点比较
    		if currentHeroNode.next == nil { // 符合条件:说明到最后一个节点了还没有匹配到所以最后插入即可
    			break
    		} else if currentHeroNode.next.tier >= newHero.tier { // 符合条件说明就刚好插在这个节点后面即可
    			break
    		}
    		currentHeroNode = currentHeroNode.next // 上序条件都不符合,currentHeroNode更新为下一个node的point值
    	}
    
    	newHero.next = currentHeroNode.next // 先让新节点指向后面的节点 (顺序很重要!)
    	currentHeroNode.next = newHero      // 再让当前节点的next指向新节点
    }
    
    // 按照英雄名称 将英雄从链表中删除
    func DeleteHeroNode(head *HeroNode, name string) {
    	currentHeroNode := head
    	flag := false
    	for {
    		if currentHeroNode.next == nil {
    			break
    		} else if currentHeroNode.next.name == name { // 符合条件表示找到
    			flag = true
    			break
    		}
    		currentHeroNode = currentHeroNode.next
    	}
    	if flag {
    		currentHeroNode.next = currentHeroNode.next.next
    	} else {
    		fmt.Println("没有该英雄...")
    	}
    }
    func ListHeroNode(head *HeroNode) { // 循环打印链表信息
    
    	currentHeroNode := head
    	if currentHeroNode.next == nil { // 先判断该链表是不是空链表,符合条件直接退出
    		fmt.Println("当前链表为空...")
    		return
    	}
    	for { // 从head节点开始。打印下一个节点的信息
    		fmt.Printf("此节点的前一个point值:%p, 此节点的后一个point值:%p\n", currentHeroNode.pre, currentHeroNode.next)
    		fmt.Printf("此英雄的point值:%p,Tier:%d,Name:%s,NickName:%s,mantra:%s\n\n",
    			currentHeroNode.next, currentHeroNode.next.tier, currentHeroNode.next.name,
    			currentHeroNode.next.nickname, currentHeroNode.next.mantra)
    
    		currentHeroNode = currentHeroNode.next // 更新临时变量为当前的指针 (必须在判断前更新)
    		if currentHeroNode.next == nil {
    			break
    		}
    
    	}
    }
    
    func main() {
    	head := &HeroNode{}
    
    	vayne := &HeroNode{
    		tier:     3,
    		name:     "vayne",
    		nickname: "薇恩",
    		mantra:   "让我们来猎杀那些陷入黑暗中的人吧",
    	}
    
    	aphelios := &HeroNode{
    		tier:     1,
    		name:     "Aphelios",
    		nickname: "厄斐琉斯",
    		mantra:   "一念一动,天人永隔",
    	}
    	verus := &HeroNode{
    		tier:     1,
    		name:     "verus",
    		nickname: "维鲁斯",
    		mantra:   "有罪之人必将知道什么叫做痛苦",
    	}
    
    	ezreal := &HeroNode{
    		tier:     2,
    		name:     "ezreal",
    		nickname: "探险家",
    		mantra:   " 是时候表演真正的技术了!",
    	}
    	// 1.第一种插入方式:在链表的最后加入,
    	InsertHeroNodeEnd(head, vayne)
    	InsertHeroNodeEnd(head, aphelios)
    	InsertHeroNodeEnd(head, ezreal)
    	InsertHeroNodeEnd(head, verus)
    	ListHeroNode(head)
    	// 2.按照tier 从小到大排序
    	InsertHeroNodeOrder(head, vayne)
    	InsertHeroNodeOrder(head, aphelios)
    	InsertHeroNodeOrder(head, ezreal)
    	InsertHeroNodeOrder(head, verus)
    	ListHeroNode(head)
    }
    


go双向链表末尾节点(append)

// 1.第一种插入方式:在链表的最后加入,
func InsertHeroNodeEnd(head *HeroNode, newHero *HeroNode) {
	if head.last == nil { //说明除了head节点 没有其他
		head.next = newHero
	} else {
		head.last.next = newHero
		newHero.pre = head.last
	}
	head.last = newHero // 最后在更新下末节点的信息
}

输出(按添加顺序)

此节点的前一个point值:0x0, 此节点的后一个point值:0xc00005c0a0
此英雄的point值:0xc00005c0a0,Tier:3,Name:vayne,NickName:薇恩,mantra:让我们来猎杀那些陷入黑暗中的人吧

此节点的前一个point值:0xc00005c050, 此节点的后一个point值:0xc00005c0f0
此英雄的point值:0xc00005c0f0,Tier:1,Name:Aphelios,NickName:厄斐琉斯,mantra:一念一动,天人永隔

此节点的前一个point值:0xc00005c0a0, 此节点的后一个point值:0xc00005c190
此英雄的point值:0xc00005c190,Tier:2,Name:ezreal,NickName:探险家,mantra: 是时候表演真正的技术了!

此节点的前一个point值:0xc00005c0f0, 此节点的后一个point值:0xc00005c140
此英雄的point值:0xc00005c140,Tier:1,Name:verus,NickName:维鲁斯,mantra:有罪之人必将知道什么叫做痛苦


go实现单链表按Tier有序插入

基本与末尾插入一样,只需要在insert的时候判断下Tier大小,从而确定插入位置

// 2.按照tier 从小到大排序。(这里的指向更改优点麻烦,最好画图理解下。有好方法在补充。)
func InsertHeroNodeOrder(head *HeroNode, newHero *HeroNode) {
	currentHeroNode := head
	for { // 让插入节点的tier currentHeroNode的下一个节点比较
		if currentHeroNode.next == nil { // 符合条件:说明到最后一个节点了还没有匹配到所以最后插入即可
			currentHeroNode.next = newHero
			newHero.pre = currentHeroNode
			break
		} else if currentHeroNode.next.tier >= newHero.tier { // 符合条件说明就刚好插在这个节点后面即可
			newHero.next = currentHeroNode.next
			newHero.pre = currentHeroNode	// 先让新节点与前后节点联系
			currentHeroNode.next.pre = newHero // 一定要先建立当前节点的下一个节点与新节点的关系
			currentHeroNode.next = newHero
			break
		}
		currentHeroNode = currentHeroNode.next // 上序条件都不符合,currentHeroNode更新为下一个node的point值
	}
}

输出(按Tier顺序)

此节点的前一个point值:0x0, 此节点的后一个point值:0xc00005c140
此英雄的point值:0xc00005c140,Tier:1,Name:verus,NickName:维鲁斯,mantra:有罪之人必将知道什么叫做痛苦

此节点的前一个point值:0xc00005c050, 此节点的后一个point值:0xc00005c0f0
此英雄的point值:0xc00005c0f0,Tier:1,Name:Aphelios,NickName:厄斐琉斯,mantra:一念一动,天人永隔

此节点的前一个point值:0xc00005c140, 此节点的后一个point值:0xc00005c190
此英雄的point值:0xc00005c190,Tier:2,Name:ezreal,NickName:探险家,mantra: 是时候表演真正的技术了!

此节点的前一个point值:0xc00005c0f0, 此节点的后一个point值:0xc00005c0a0
此英雄的point值:0xc00005c0a0,Tier:3,Name:vayne,NickName:薇恩,mantra:让我们来猎杀那些陷入黑暗中的人吧


go实现链表删除

// 按照英雄名称 将英雄从链表中删除
func DeleteHeroNode(head *HeroNode, name string) {
	currentHeroNode := head
	flag := false
	for {
		if currentHeroNode.next == nil {
			break
		} else if currentHeroNode.next.name == name { // 符合条件表示找到
			flag = true
			break
		}
		currentHeroNode = currentHeroNode.next
	}
	if flag {
		if currentHeroNode.next.next == nil { //说明要删除的节点就是末节点
			currentHeroNode.next = nil
		} else {
			currentHeroNode.next.next.pre = currentHeroNode
			currentHeroNode.next = currentHeroNode.next.next
		}

	} else {
		fmt.Println("没有该英雄...")
	}
}

改查逻辑类似

posted on 2020-06-14 18:33  3rdworld  阅读(83)  评论(0编辑  收藏  举报