golang实现单向,双向,环形单向链表:增(两种方式)删改查,链表所有结点展示...双向链表,环形单项链表完整代码

golang单项链表

  1. 头部代码:引用一些包,创建链表数据结构
package utils
import (
	"fmt"
)
//单链表 末尾添加
type SingleNode struct{
	No int //编号
	Name string //名称
	Next *SingleNode //表示指向下一个节点
}
  1. 增加:分为两种,第二种比较常用

第一种添加:

//链表插入一个节点
//第一种添加:在单链表的最后加入
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
}
  1. 删除 :删除传入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
}

  1. 修改 :修改对应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
	
}
  1. 查询:查询对应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
	
}
  1. 所有结点展示:遍历展示链表的所有结点
//显示链表的所有节点信息
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
}
  1. 测试增删改查:主要测试第二种添加。单链表封装在文件夹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, 旺财] ==>
  1. 结果
# 执行 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
}

  1. 环形单项链表:需要注意删除首结点时要从新接收这个返回值,获取列表时传入新接收到的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

}

环形链表测试代码截图示例:注意红色箭头指向部分
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员D日常

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值