Golang——实现双链表

双链表介绍

双链表(Doubly Linked List)是一种链表数据结构,它的每个节点都有两个链接:一个指向前一个节点(如果有的话),另一个指向下一个节点(如果有的话)。这使得双链表在遍历、插入和删除节点时都具有一定的灵活性。

双链表和单链表的基本操作有很多相似的。

因此这里提供一篇单链表基本操作的博客:Golang——实现单链表-CSDN博客

双链表与单链表的区别

  1. 指针数量
    • 单链表(Singly Linked List)中的每个节点只有一个指向下一个节点的指针。
    • 双链表中的每个节点有两个指针:一个指向前一个节点,另一个指向下一个节点。
  2. 遍历方向
    • 单链表只能从头节点开始,沿着指针方向向前遍历到尾节点。
    • 双链表可以从头节点开始向前遍历,也可以从尾节点开始向后遍历,或者从任何中间节点开始双向遍历。
  3. 插入和删除操作
    • 在单链表中,插入和删除节点需要知道前一个节点(除了头节点外)。例如,要删除一个节点,你需要知道该节点的前一个节点,以便更新其next指针。
    • 在双链表中,插入和删除节点时,你可以直接访问前一个节点和下一个节点,这使得操作更加简单和直接。
  4. 应用场景
    • 单链表通常用于只需要单向遍历的场景,如实现简单的栈或队列。
    • 双链表则更适用于需要双向遍历或快速访问前后节点的场景,如实现双向队列(deque)或需要频繁进行节点插入和删除操作的应用。

本文通过定义结构体来实现双链表的操作。id为链表节点的id,name为id对应节点的数据,pre表示前一个节点的数据,next表示下一个节点的数据。双链表是双向连接的因此比单链表多创建一个pre

type Twoline struct {
	id   int
	name string
	pre  *Twoline 
	next *Twoline 
}

Input方法,实现添加节点操作

这里的操作与单链表添加节点的操作类似,首先定义一个辅助节点tead通过循环找到链表的最后一个节点,然后进行插入操作,将最后一个节点的下一个节点定义为要插入的节点,将要插入的节点的上一个节点定义为最后一个节点。

func Input(head *Twoline, hero *Twoline) {
	tead := head
	for {
		if tead.next == nil {
			break
		}
		tead = tead.next
	}
	tead.next = hero
	hero.pre = tead
}

Input2方法,实现顺序添加节点操作

首先还是定义一个辅助节点,这次还另外定义一个flag为了判断要插入的节点是否已经存在。通过辅助节点进行判断插入的节点的id,并进行插入对应位置。这里将要插入的节点定义为hero,辅助节点为tead。进行插入操作时先将hero的下一个节点定义为tead的下一个节点,然后将hero的上一个节点改为tead节点,然后进行判断辅助节点是否为链表的最后一个节点如果不是就将tead的下一个节点的前一个节点设为hero,并将tead的下一个节点设为hero,如果辅助节点是链表的最后一个节点,那么直接将tead的下一个节点设为hero。

func Input2(head *Twoline, hero *Twoline) {
	tead := head
	flag := true
	for {
		if tead.next == nil {
			break
		} else if tead.next.id > hero.id {
			break
		} else if tead.next.id == hero.id {
			flag = false
			break
		}
		tead = tead.next
	}
	if !flag {
		fmt.Println("已经存在", hero.id)
		return
	} else {
		hero.next = tead.next
		hero.pre = tead
		if tead.next != nil {
			tead.next.pre = hero
		}
		tead.next = hero
	}
}

DelectNode方法,实现链表删除节点操作

通过辅助节点以及flag进行寻找要删除的节点的id,找到后将tead的下一个节点的改为下一个节点的下一个节点,直接将要删除的节点的给忽略掉,go语言的将会将其认定为垃圾从而进行回收,然后进行判断tead的下一个节点是否为空,若是不为空则将tead的下一个节点的前一个节点改为tead。

func DelectNode(head *Twoline, id int) {
	tead := head
	flag := false
	for {
		if tead.next == nil {
			break
		} else if tead.next.id == id {
			//说明找到了
			flag = true
			break
		}
		tead = tead.next
	}
	if flag {
		tead.next = tead.next.next
		if tead.next != nil {
			tead.next.pre = tead
		}
	} else {
		fmt.Println("删除id不存在", id)
	}
}

Show方法,实现双链表的显示操作

这里的操作与单链表类似,具体可以看单链表的显示操作,这里不做讲解。

func Show(head *Twoline) {
	tead := head
	if tead.next == nil {
		fmt.Println("空链表")
		return
	}
	for {
		fmt.Printf("[%d ,%s ]==>", tead.next.id, tead.next.name)
		tead = tead.next
		if tead.next == nil {
			break
		}
	}
}

Show2方法逆序显示双链表的节点操作。

这里的前期操作和顺序显示一样,但在循环显示时需要注意的是这里tead是前面循环得到的双链表的最后那一个节点因此输出时直接输出他的id和name即可,并将其改为前一个节点,进而继续循环输出。

func Show2(head *Twoline) {
	tead := head
	//	让tead 定位到双链表的最后节点
	if tead.next == nil {
		fmt.Println("空链表")
		return
	}
	for {
		if tead.next == nil {
			break
		}
		tead = tead.next
	}

	//	遍历链表
	for {
		fmt.Printf("[%d , %s]==>", tead.id, tead.name)
		tead = tead.pre
		if tead.pre == nil {
			break
		}
	}
}

主函数

func main() {
	head := &Twoline{}
	hero1 := &Twoline{
		id:   1,
		name: "掌门",
	}
	hero2 := &Twoline{
		id:   2,
		name: "花花",
	}
	hero3 := &Twoline{
		id:   3,
		name: "明明",
	}
	hero4 := &Twoline{
		id:   4,
		name: "东东",
	}
	Input2(head, hero1)
	Input2(head, hero3)
	Input2(head, hero4)
	Input2(head, hero2)
	Show(head)
	fmt.Println()
	fmt.Println("逆序显示")
	Show2(head)
	fmt.Println()
	fmt.Println("删除节点id为1的节点")
	DelectNode(head, 1)
	Show(head)
}

整体代码运行结果

  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值