链表学习-双向链表go实现 [3]
go实现双向链表
示例代码
-
定义一个存储英雄信息的结构
HeroNode
,其中next
为下一个英雄节点的内存地址,last
为最后一个英雄节点的内存地址(append时不用遍历) -
初始化
head
节点,和四个英雄节点 -
InsertHeroNodeEnd
末尾插入;InsertHeroNodeOrder
比对Tire的大小,找到临界面值 -
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("没有该英雄...")
}
}
改查逻辑类似