golang单项链表
- 头部代码:引用一些包,创建链表数据结构
package utils
import (
"fmt"
)
//单链表 末尾添加
type SingleNode struct{
No int //编号
Name string //名称
Next *SingleNode //表示指向下一个节点
}
- 增加:分为两种,第二种比较常用
第一种添加:
//链表插入一个节点
//第一种添加:在单链表的最后加入
func AddSingleNode(head *SingleNode, newSingleNode *SingleNode){
//1.先找到链表的最后这个节点
//2.创建一个辅助节点
temp := head
for{
if temp.Next == nil{//找到最后一个
break
}
temp = temp.Next //不断的移动指向下一个结点
}
//3.将newSingleNode 加入链表的最后
temp.Next = newSingleNode
return
}
第二种添加(常用):
//第二种添加:根据no的编号从小到大插入,编号是唯一的
func InsertSingleNode(head *SingleNode, newSingleNode *SingleNode){
//1.找到恰当的节点
//2.创建一个辅助节点
temp := head
flag := true //默认可以插入链表
//让插入的节点的no,和temp的下的一个节点no进行比较
for{
if temp.Next == nil{
break
}else if temp.Next.No > newSingleNode.No{//排序;说明newSingleNode应该插入temp后面【如果编号有相等的,需要修改为:temp.No >= newSingleNode.No】
break
}else if temp.Next.No == newSingleNode.No{//说明这个链表已经存在这个No,不能插入
flag = false
break
}
temp = temp.Next
}
if !flag{
fmt.Println("该编号已经存在,不能插入")
return
}else{
newSingleNode.Next = temp.Next
temp.Next = newSingleNode
}
return
}
- 删除 :删除传入No的结点
//删除No= id的结点
func DeleteSingleNode(head *SingleNode, id int){
temp := head
flag := true //代表找到
//找到要删除的节点
for{
if temp.Next.No == id{
break
}else if temp.Next == nil{//找到最后一个节点
flag = false
break
}else{
temp = temp.Next
}
}
if flag{
temp.Next = temp.Next.Next
fmt.Println("delete ok...")
}else{
fmt.Printf("要删除对应id=%d的链表不存在\n", id)
}
return
}
- 修改 :修改对应No的节点信息
//修改No=id的结点的SingleNode
func EditSingleNode(head *SingleNode, id int, newSingleNode *SingleNode){
temp := head
flag := false
for{
if temp.Next == nil{
//已经找到结尾未找到
break
}else if temp.Next.No == id{//找到
flag = true
break
}else{
temp = temp.Next
}
}
if flag{
newSingleNode.Next = temp.Next.Next
temp.Next = newSingleNode
return
}
fmt.Println("抱歉,修改失败,未找到该结点")
return
}
- 查询:查询对应No的结点
//查找No= id的节点
func FindSingleNode(head *SingleNode, id int){
temp := head
flag := false
for{
if temp.Next == nil{
//已经找到结尾未找到
break
}else if temp.Next.No == id{
flag = true
break
}else{
temp = temp.Next
}
}
if flag{
fmt.Printf("恭喜,找到了对应id=%d的节点:[%d, %s]", id, temp.Next.No, temp.Next.Name)
fmt.Println()
return
}
fmt.Println("抱歉,未找到该节点")
return
}
- 所有结点展示:遍历展示链表的所有结点
//显示链表的所有节点信息
func ListSingleNode(head *SingleNode){
//创建一个辅助节点
temp := head
if temp.Next == nil{
fmt.Println("空链表...")
return
}
for{
fmt.Printf("[%d, %s] ==>", temp.Next.No, temp.Next.Name)
temp = temp.Next
if temp.Next == nil{//已经到达尾部
break
}
}
fmt.Println()
return
}
- 测试增删改查:主要测试第二种添加。单链表封装在文件夹
utils
下,而在main
包下进行的调用测试
//创建一个头节点
head := &utils.SingleNode{}
single1 := &utils.SingleNode{
No : 1,
Name : "张三",
}
single4 := &utils.SingleNode{
No : 3,
Name : "王五",
}
single2 := &utils.SingleNode{
No : 2,
Name : "王麻子",
}
single3 := &utils.SingleNode{
No : 4,
Name : "旺财",
}
updateSingle := &utils.SingleNode{
No : 2,
Name : "李四",
}
utils.InsertSingleNode(head, single1)
utils.InsertSingleNode(head, single4)
utils.InsertSingleNode(head, single2)
utils.InsertSingleNode(head, single3)
utils.ListSingleNode(head)//原始链表 `预期结果`:[1, 张三] ==>[2, 王麻子] ==>[3, 王五] ==>[4, 旺财] ==>
utils.FindSingleNode(head, 2)//查找对应id的链表
utils.EditSingleNode(head, 2, updateSingle)//修改id=2的结点
utils.ListSingleNode(head)//修改后的结点链表 `预期结果`:[1, 张三] ==>[2, 李四] ==>[3, 王五] ==>[4, 旺财] ==>
utils.DeleteSingleNode(head, 2)//删除对应id链表
utils.ListSingleNode(head) //删除后最新的链表 `预期结果`:[1, 张三] ==>[3, 王五] ==>[4, 旺财] ==>
- 结果
# 执行 utils.ListSingleNode(head)
[1, 张三] ==>[2, 王麻子] ==>[3, 王五] ==>[4, 旺财] ==>
# 执行 utils.FindSingleNode(head, 2)
恭喜,找到了对应id=2的节点:[2, 王麻子]
# 执行 utils.EditSingleNode(head, 2, updateSingle)
恭喜,更新了对应id=2的节点:[2, 李四]
# 执行 utils.ListSingleNode(head)
[1, 张三] ==>[2, 李四] ==>[3, 王五] ==>[4, 旺财] ==>
# 执行 utils.DeleteSingleNode(head, 2)
delete ok...
# 执行 utils.ListSingleNode(head)
[1, 张三] ==>[3, 王五] ==>[4, 旺财] ==>
测试执行结果截图:
9. 双向链表完整代码
package utils
import (
"fmt"
)
type DoubleNode struct{
No int
Name string
Pre *DoubleNode //前一个节点
Next *DoubleNode //后一个节点
}
//链表插入一个节点
//第一种添加:在单链表的最后加入
func AddDoubleNode(head *DoubleNode, newDoubleNode *DoubleNode){
//1.先找到链表的最后这个节点
//2.创建一个辅助节点
temp := head
for{
if temp.Next == nil{//找到最后一个
break
}
temp = temp.Next //不断的移动指向下一个结点
}
//3.将newDoubleNode 加入链表的最后
temp.Next = newDoubleNode
newDoubleNode.Pre = temp
return
}
//第二种添加:根据no的编号从小到大插入,编号是唯一的
func InsertDoubleNode(head *DoubleNode, newDoubleNode *DoubleNode){
//1.找到恰当的节点
//2.创建一个辅助节点
temp := head
flag := true //默认可以插入链表
//让插入的节点的no,和temp的下的一个节点no进行比较
for{
//temp.Next = nil表示已到最后一个结点 || 排序;说明newDoubleNode应该插入temp后面【如果编号有相等的,需要修改为:temp.No >= newDoubleNode.No】
if temp.Next == nil || temp.Next.No > newDoubleNode.No{
break
}else if temp.Next.No == newDoubleNode.No{//说明这个链表已经存在这个No,不能插入
flag = false
break
}
temp = temp.Next
}
if flag{
newDoubleNode.Next = temp.Next
newDoubleNode.Pre = temp
if(temp.Next != nil){//判断是否为最后一个链表结点
temp.Next.Pre = newDoubleNode
}
temp.Next = newDoubleNode
}else{
fmt.Println("该编号已经存在,不能插入")
}
return
}
//修改No=id的结点的DoubleNode
func EditDoubleNode(head *DoubleNode, id int, updateDoubleNode *DoubleNode){
temp := head
flag := false
for{
if temp.Next == nil{
//已经找到结尾未找到
break
}else if temp.Next.No == id{//找到
flag = true
break
}
temp = temp.Next
}
if flag{
updateDoubleNode.Next = temp.Next.Next
temp.Next = updateDoubleNode
if temp.Next != nil{
updateDoubleNode.Pre = temp.Pre
}
return
}
fmt.Println("抱歉,修改失败,未找到该结点")
return
}
//删除No= id的结点[双向链表的自我结点删除]
func DeleteDoubleNode(head *DoubleNode, id int){
temp := head
flag := true //代表找到
//找到要删除的节点
for{
if temp.Next.No == id{
break
}else if temp.Next == nil{//找到最后一个节点
flag = false
break
}else{
temp = temp.Next
}
}
if flag{
temp.Next = temp.Next.Next
if temp.Next != nil{//判断是否为最后一个链表结点
temp.Next.Pre = temp
}
fmt.Println("delete ok...")
}else{
fmt.Printf("要删除对应id=%d的链表不存在\n", id)
}
return
}
//显示链表的所有节点信息:正向打印
func ListDoubleNode(head *DoubleNode){
//创建一个辅助节点
temp := head
if temp.Next == nil{
fmt.Println("空链表...")
return
}
fmt.Println("正向打印链表结点:")
for{
fmt.Printf("[%d, %s] ==>", temp.Next.No, temp.Next.Name)
temp = temp.Next
if temp.Next == nil{//已经到达尾部
break
}
}
return
}
//显示链表的所有节点信息:逆向打印
func DescListDoubleNode(head *DoubleNode){
//创建一个辅助节点
temp := head
if temp.Next == nil{
fmt.Println("空链表...")
return
}
//先找到最后一个结点
for{
if temp.Next == nil{
break
}
temp = temp.Next
}
//此时temp以是正向数最后一个结点
fmt.Println("逆向打印链表结点:")
for{
fmt.Printf("[%d, %s] ==>", temp.No, temp.Name)
temp = temp.Pre
if temp.Pre == nil{//已经到达首部结点
break
}
}
return
}
- 环形单项链表:需要注意删除首结点时要从新接收这个返回值,获取列表时传入新接收到的head
package utils
import (
"fmt"
)
type CricleSingleNode struct{
No int
Name string
Next *CricleSingleNode
}
func InsertCricleSingleNode(head *CricleSingleNode, newNode *CricleSingleNode){
//判断是否为第一个结点
if head.Next == nil{
head.No = newNode.No
head.Name = newNode.Name
head.Next = head //一个结点时也要是环形
return
}
//定义临时变量,找到环形的最后一个结点
tempNode := head
for{
if tempNode.Next == head{
break
}
tempNode = tempNode.Next
}
tempNode.Next = newNode
newNode.Next = head
return
}
//输出环形链表所有结点
func ListCricleSingleNode(head *CricleSingleNode){
tempNode := head
if tempNode.Next == nil{//是一个空链表
fmt.Println("这是一个空的环形链表")
return
}
for{
fmt.Printf("[No = %d, Name = %s]-->", tempNode.No, tempNode.Name)
if tempNode.Next == head{//头和尾相遇了
fmt.Printf("[No = %d, Name = %s]", tempNode.Next.No, tempNode.Next.Name)
break
}
tempNode = tempNode.Next
}
fmt.Println()
return
}
//删除环形链表的某一结点【需要注意删除首结点时要从新接收这个返回值,获取列表时传入新接收到的head】
func DeleteCricleSingleNode(head *CricleSingleNode, id int) *CricleSingleNode{
tempNode := head //指向环形首部
if tempNode == nil{
fmt.Println("这是一个空的环形链表")
return head
}
//如果只有一个结点
if tempNode.Next == head{
tempNode.Next = nil
return head
}
//将helper 定位到最后
helpNode := head //指向环形尾部
for {
if helpNode.Next == head{
break
}
helpNode = helpNode.Next
}
flag := false //删除了
for{
if tempNode.Next == head{//找到了最后一个
flag = true //到结尾了还没删除
break
}
if tempNode.No == id {
if tempNode == head{//删除的是头部
head = head.Next
}
helpNode.Next = tempNode.Next
return head
}
tempNode = tempNode.Next
helpNode = helpNode.Next
}
if flag{
if tempNode.No == id{
helpNode.Next = tempNode.Next
}else{
fmt.Println("没有找到要删除的结点")
}
}
return head
}
环形链表测试代码截图示例:注意红色箭头指向部分