《大话数据结构》学习笔记 —— 03 双向链表(golang实现)

本文深入解析了双向链表的定义、结构与实现方法,详细介绍了如何使用Go语言进行双向链表的构造、插入、删除等操作,是理解双向链表核心概念及应用实践的全面指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


循环链表


定义

双向链表是在单链表的每个结点中,再设置一个指向前驱结点的指针域。


代码实现

package DoubleLinkling

// 双向链表结点
type DoubleLinkNode struct {
	value interface{}

	// 上一个结点
	prev *DoubleLinkNode

	// 下一个结点
	next *DoubleLinkNode
}

// 构造结点
func NewDoubleLinkNode(data interface{}) *DoubleLinkNode {
	return &DoubleLinkNode{
		value: data,
		prev:  nil,
		next:  nil,
	}
}

// 返回数据
func (node *DoubleLinkNode) Value() interface{} {
	return node.value
}

// 返回上一个结点
func (node *DoubleLinkNode) Prev() *DoubleLinkNode {
	return node.prev
}

// 返回下一个结点
func (node *DoubleLinkNode) Next() *DoubleLinkNode {
	return node.next
}

// 定义双向链表接口
type DoubleLink interface {

	// 返回第一个数据结点
	GetFirstNode() *DoubleLinkNode

	// 插入结点(头插法)
	InsertNodeFront(node *DoubleLinkNode)

	// 插入结点(尾插法)
	InsertNodeBack(node *DoubleLinkNode)

	// 插入某结点前
	InsertNodeValueFront(dest interface{}, node *DoubleLinkNode) bool

	// 插入某结点后
	InsertNodeValueBack(dest interface{}, node *DoubleLinkNode) bool

	// 获取指定索引上的结点
	GetNodeAtIndex(index int) *DoubleLinkNode

	// 删除结点
	DeleteNode(dest *DoubleLinkNode) bool

	// // 删除指定索引上的结点
	// DeleteAtIndex(index int) bool

	// 返回字符串
	String() string
}

// 双链表
type DoubleLinkList struct {

	// 头指针
	head *DoubleLinkNode

	// 长度
	length int
}

// 初始化双向链表
func NewDoubleLinkList() *DoubleLinkList {

	// 初始化头结点
	head := NewDoubleLinkNode(nil)

	return &DoubleLinkList{
		head:   head,
		length: 0,
	}
}

// 获取链表长度
func (dist *DoubleLinkList) GetLength() int {
	return dist.length
}

// 获取第一个数据结点
func (dist *DoubleLinkList) GetFirstNode() *DoubleLinkNode {
	return dist.head.next
}

// 获取指定索引上的结点
func (dist *DoubleLinkList) GetNodeAtIndex(index int) *DoubleLinkNode {

	// 索引越界
	if index > dist.length-1 || index < 0 {
		return nil
	}

	// 备份头结点
	bak := dist.head

	// 向后循环
	for index > -1 {
		bak = bak.next
		index--
	}

	return bak
}

// 头部插入
func (dist *DoubleLinkList) InsertNodeFront(node *DoubleLinkNode) {

	// 空链表
	if dist.head.next == nil {

		// 第一个数据结点设为新结点
		dist.head.next = node

		// 新结点next指针指向nil
		node.next = nil

		// 新结点prev指针指向头结点
		node.prev = dist.head

		dist.length++
		return
	}

	// 备份头结点
	bak := dist.head

	// 新结点的next指针,指向原来的第一个数据结点
	node.next = bak.next

	// 第一个数据结点的prev指向新结点
	bak.next.prev = node

	// 头结点的next指针指向新结点
	bak.next = node

	// 新结点的prev指针指向头结点
	node.prev = bak

	dist.length++
	return
}

// 尾部插入
func (dist *DoubleLinkList) InsertNodeBack(node *DoubleLinkNode) {

	// 空链表
	if dist.head.next == nil {

		// 第一个数据结点设为新结点
		dist.head.next = node

		// 新结点next指针指向nil
		node.next = nil

		// 新结点prev指针指向头结点
		node.prev = dist.head

		dist.length++
		return
	}

	// 备份头结点
	bak := dist.head

	// 循环到链表末尾
	for bak.next != nil {
		bak = bak.next
	}

	// 终端结点的指针指向新结点
	bak.next = node

	// 新结点的prev指针指向原来的终端结点
	node.prev = bak

	dist.length++
	return
}

// 插入某结点前
func (dist *DoubleLinkList) InsertNodeValueFront(dest interface{}, node *DoubleLinkNode) bool {

	// 备份头结点
	bak := dist.head

	// 循环到末尾,直至找到目标结点
	for bak.next != nil && bak.next.value != dest {
		bak = bak.next
	}

	// 找到
	if bak.next.value == dest {

		// 目标结点的上一个数据结点的next指针,赋值给新结点的指针
		node.next = bak.next

		// 新结点的prev指针指向bak
		node.prev = bak

		// 目标结点的prev指针指向node结点
		bak.next.prev = node

		// 目标结点的上一个数据结点的next指针,指向新结点
		bak.next = node

		dist.length++
		return true
	}

	return false
}

// 插入某结点后
func (dist *DoubleLinkList) InsertNodeValueBack(dest interface{}, node *DoubleLinkNode) bool {

	// 备份头结点
	bak := dist.head

	// 循环到末尾,直至找到目标结点
	for bak.next != nil && bak.next.value != dest {
		bak = bak.next
	}

	// 找到
	if bak.next.value == dest {

		// 如果目标结点有后续结点
		if bak.next.next != nil {
			// 目标结点的后续结点的prev指针赋值给新结点
			bak.next.next.prev = node
		}

		// 目标结点的next指针,赋值给新结点的next指针
		node.next = bak.next.next

		// 目标结点的next指针指向新结点
		bak.next.next = node

		// 新结点的prev指针,指向目标结点
		node.prev = bak.next

		dist.length++
		return true
	}

	return false
}

// 删除结点
func (dist *DoubleLinkList) DeleteNode(dest *DoubleLinkNode) bool {

	// 备份头结点
	bak := dist.head

	// 结点为空
	if dest == nil {
		return false
	}

	// 循环到末尾,直至找到目标结点
	for bak.next != nil && bak.next != dest {
		bak = bak.next
	}

	// 找到
	if bak.next == dest {

		// 如果目标结点有后续结点
		if bak.next.next != nil {
			// 目标结点的后续结点的prev指针赋值给当前结点
			bak.next.next.prev = bak
		}

		// 目前结点的指针赋值给目标结点的上一个数据结点的指针
		bak.next = bak.next.next

		dist.length--
		return true
	}

	return false
}

// 删除指定索引上的结点
func (dist *DoubleLinkList) DeleteAtIndex(index int) bool {

	// 索引越界
	if index > dist.length-1 || index < 0 {
		return false
	}

	// 备份头结点
	bak := dist.head

	// 向后循环,找到前一个结点
	for index > 0 {
		bak = bak.next
		index--
	}

	// 如果目标结点有后续结点
	if bak.next.next != nil {
		// 目标结点的后续结点的prev指针赋值给前一个结点
		bak.next.next.prev = bak
	}

	// 目前结点的next指针,赋值给目标结点的上一个数据结点的next指针
	bak.next = bak.next.next

	dist.length--
	return true
}

// 返回字符串
func (dist *DoubleLinkList) String() string {

	var distString1 string
	var distString2 string

	// 头结点
	p := dist.head

	// 循环输出
	for p.next != nil {
		distString1 += fmt.Sprintf("%v-->", p.next.value)
		p = p.next
	}
	distString1 += fmt.Sprintf("nil")
	distString1 += "\n"

	for p != dist.head {
		distString2 += fmt.Sprintf("<--%v", p.value)
		p = p.prev
	}
	distString1 += fmt.Sprintf("nil")

	return distString1 + distString2 + "\n"
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值