楔子
go单项链表学习,记录学习过程失败情况
插入重复 元素,出现异常
重复插入会形成死循环。因为那个节点的next指向了自己。
代码如下
// failed:如果重复插入会失败
func InsertHeroNodeBySort(head *HeroNode, newHeroNode *HeroNode) {
//思路
//1. 先找到该链表的最后这个结点
//2. 创建一个辅助结点[跑龙套, 帮忙]
temp := head
for {
if temp.next == nil { //表示找到最后
temp.next = newHeroNode //链表为空直接插入
break
}
// |如果 链表中是no为[3],要插入的是2
if temp.next.no >= newHeroNode.no {
//下面这两行切记顺序不可变
newHeroNode.next = temp.next
temp.next = newHeroNode
break
}
//|如果 链表中是no为[2,5],要插入的是3
if temp.next.no < newHeroNode.no {
if temp.next.next == nil {
//如果 链表中是no为[2, ],要插入的是3
temp.next.next = newHeroNode
break
} else {
//|如果 链表中是no为[2,5],要插入的是3
//temp.next.next = newHeroNode
//break
}
}
temp = temp.next
}
//3. 将newHeroNode加入到链表的最后
}
完整
package main
import (
"fmt"
)
//单链表|
type HeroNode struct {
no int
name string
nickname string
next *HeroNode //下一个英雄
}
func (h *HeroNode) String() string {
return fmt.Sprintf("[%d %s %s]==>", h.no, h.name, h.nickname)
}
func InsertHeroNode(head *HeroNode, newHeroNode *HeroNode) {
//思路
//1. 先找到该链表的最后这个结点
//2. 创建一个辅助结点[跑龙套, 帮忙]
temp := head
for {
if temp.next == nil { //表示找到最后
break
}
temp = temp.next // 让temp不断的指向下一个结点
}
//3. 将newHeroNode加入到链表的最后
temp.next = newHeroNode
}
//显示链表的所有结点信息
func ListHeroNode(head *HeroNode) {
//1. 创建一个辅助结点[跑龙套, 帮忙]
temp := head
// 先判断该链表是不是一个空的链表
if temp.next == nil {
fmt.Println("空空如也。。。。")
return
}
//2. 遍历这个链表
for {
fmt.Printf("[%d , %s , %s]==>", temp.next.no,
temp.next.name, temp.next.nickname)
//判断是否链表后
temp = temp.next
if temp.next == nil {
break
}
}
}
func ListHeroNode_my(head *HeroNode) {
//1 创建临时结点
temp := head
//选判断该链表是不是空链表
for {
if temp.next == nil {
break
}
temp = temp.next
fmt.Print(temp)
}
}
func main() {
//一个头结点
head := &HeroNode{}
// 创建一个新的 heronode
hero1 := &HeroNode{
no: 1,
name: "宋江",
nickname: "及时雨",
}
hero5 := &HeroNode{
no: 5,
name: "关胜",
nickname: "大刀",
}
hero7 := &HeroNode{
no: 7,
name: "林冲",
nickname: "豹子头",
}
InsertHeroNodeBySort(head, hero7)
InsertHeroNodeBySort(head, hero5)
InsertHeroNodeBySort(head, hero1)
ListHeroNode_my(head)
DelHernNode(head,3)
fmt.Println()
ListHeroNode_my(head)
}
func DelHernNode(head *HeroNode, delId int) {
temp := head
flag := false
//TODO 找到要删除的节点
for ; ; {
if temp.next == nil { //插入到最后
break
} else if temp.next.no == delId { //此位置调整之后即可为从大到小
//找到删除的节点
flag = true
break
}
temp = temp.next
}
if flag{
temp.next = temp.next.next
}
}
//韩顺平 方法
func InsertHeroNode2(head *HeroNode, newHeroNode *HeroNode) {
//思路
//1. 先找到该链表的最后这个结点
//2. 创建一个辅助结点[跑龙套, 帮忙]
temp := head
flag := true
// 让插入的节点no 和temp的下一个节点no比较
for ; ; {
if temp.next == nil { //插入到最后
break
} else if temp.next.no >= newHeroNode.no { //此位置调整之后即可为从大到小
//应该插入temp
break
} else if temp.next.no == newHeroNode.no {
flag = false
break
}
temp = temp.next
}
if !flag {
fmt.Println("已经有此英雄")
return
} else {
newHeroNode.next = temp.next
temp.next = newHeroNode
}
}
// failed:如果重复插入会失败
func InsertHeroNodeBySort(head *HeroNode, newHeroNode *HeroNode) {
//思路
//1. 先找到该链表的最后这个结点
//2. 创建一个辅助结点[跑龙套, 帮忙]
temp := head
for {
if temp.next == nil { //表示找到最后
temp.next = newHeroNode //链表为空直接插入
break
}
// |如果 链表中是no为[3],要插入的是2
if temp.next.no >= newHeroNode.no {
//下面这两行切记顺序不可变
newHeroNode.next = temp.next
temp.next = newHeroNode
break
}
//如果 链表中是no为[3],要插入的是3
if temp.next.no == newHeroNode.no {
//重复有问题
break
}
//TODO 对照韩顺平 老师的 我才知道,这部分是多余的
//|如果 链表中是no为[2,5],要插入的是3
//if temp.next.no < newHeroNode.no {
// if temp.next.next == nil {
// //如果 链表中是no为[2, ],要插入的是3
// temp.next.next = newHeroNode
// break
// }
//}
temp = temp.next
}
}
环形单向链表
package main
import (
"fmt"
)
type CatNode struct {
no int //
name string
next *CatNode
}
func (c *CatNode) String() string {
return fmt.Sprintf("[%d %s]=>", c.no, c.name)
}
func main() {
//初始化 一个环形链表的头节点
head := &CatNode{}
cat1 := &CatNode{no: 1, name: "tom",}
cat2 := &CatNode{no: 2, name: "tom2",}
cat3 := &CatNode{no: 3, name: "tom3",}
//cat4 := &CatNode{no: 4, name: "tom4",}
//cat5 := &CatNode{no: 5, name: "tom5",}
//cat6 := &CatNode{no: 6, name: "tom6",}
insertCatNode(head, cat1)
insertCatNode(head, cat2)
insertCatNode(head, cat3)
ListCircleLink(head)
node := DelCatNode(head, 2)
ListCircleLink(node)
}
//思路
/*************************************
1 先让temp指向head
2 让helper指向环形链表最后。
3 让temp和要删除的ID比较,如果相同则通过helper完成删除,但是要考虑 是否是头结点。
*************************************/
//删除一只猫
func DelCatNode(head *CatNode, id int) *CatNode {
temp := head
helper := head
//空链表
if temp.next == nil {
fmt.Println("这是一个空的环形链表,不能删除")
return head
}
//如果只有一个结点
if temp.next == head { //只有一个结点
if temp.no == id {
temp.next = nil
}
return head
}
//将helper 定位到链表最后
for {
if helper.next == head {
break
}
helper = helper.next
}
//如果有两个包含两个以上结点
flag := true
for {
if temp.next == head { //如果到这来,说明我比较到最后一个【最后一个还没比较】
break
}
if temp.no == id {
if temp == head { //说明删除的是头结点
head = head.next
}
//恭喜找到., 我们也可以在直接删除
helper.next = temp.next
fmt.Printf("猫猫=%d\n", id)
flag = false
break
}
temp = temp.next //移动 【比较】
helper = helper.next //移动 【一旦找到要删除的结点 helper】
}
//这里还有比较一次
if flag { //如果flag 为真,则我们上面没有删除
if temp.no == id {
helper.next = temp.next
fmt.Printf("猫猫=%d\n", id)
} else {
fmt.Printf("对不起,没有no=%d\n", id)
}
}
return head
}
func insertCatNode(head *CatNode, newCat *CatNode) {
// 判断是不是第一只猫
if head.next == nil {
head.no = newCat.no
head.name = newCat.name
head.next = head //形成一个环形|此处不要写成newCat
return
}
//定义一个临时变量。帮助找到环形最后一个节点
temp := head
for ; ; {
if temp.next == head {
break
}
temp = temp.next
}
// 加入链表中
temp.next = newCat
newCat.next = head
}
func ListCircleLink(head *CatNode) {
fmt.Println()
temp := head
if temp.next == nil {
fmt.Println(" 空的环形链表")
return
}
for {
fmt.Print(temp)
if temp.next == head {
break
}
temp = temp.next
}
}