Go语言数据结构怎么实现抄一个list示例

list是个啥

在开始做之前,还是要先了解一下链表这个数据结构 ,长话短说:

  • 线性表的链式存储结构称为链表,如:

a.next = b
a.prev = c
b.next = c
b.prev = a
c.next = a
c.prev = b

这就是一个双向循环链表

  • 链表可以提升存储空间的利用率,实现了存储空间动态管理的链式存储结构

接下来,我们来看看Go官方都为这个list提供了哪些操作,我们逐一实现

Go语言数据结构怎么实现抄一个list示例

  • New:创建一个链表

  • Init:初始化一个链表

  • Back:返回链表中的最后一个元素

  • Front:返回链表中的第一个元素

  • InsertAfter(e,at):将e加入at元素后

  • InsertBefore(e,at):将e加入at元素前

  • Len:返回list的长度

  • PushBack(e):将e成为链表的最后一个元素

  • PushFront(e):将e成为链表的第一个元素

  • Remove(e):将list上的e删除

list结构

定义list结构,以及list内部node节点的结构,这里采用struct实现

type Element struct {
	prev, next *Element
	Value      any
}
type List struct {
	root Element
	len  int
}

Init & New

Init就是提供初始化一个环链表的方法,并返回这个环形链表

之所以把 Init 和 New 放在一起,是因为在 New 函数中其实就是对 Init 的一层包装,这样就可以实现Go中的包名.New方法,比如:errors.New()

// 初始化一个 环list
func (list *List) Init() *List {
	// 形成环
	list.root.next = &list.root
	list.root.prev = &list.root
	list.len = 0
	return list
}
func NewList() *List {
	return new(List).Init()
}

InsertAfter & InsertBefore & PushBack & PushFront

这两个方法的作用类似,就是将 e 插入到 at 的后/前位置

这里我们先看一个图:

Go语言数据结构怎么实现抄一个list示例

这个图片就是一个双向环形链表,我们要在这个里面进行插入元素操作,比如,我们要插入 e 到 e1 前面我们应该怎么做?

  • 将e的下一个变为e1:e.next = e1

  • 将e的上一个变为e1的上一个:e.prev = e1.prev

  • 将e的上一个的下一个变为自己:e.prev.next = e

  • 将e的下一个的上一个变为自己:e.next.prev = e

这样就完成了插入,回到方法实现上,一个是插入之后,一个插入之前,那么我们是不是可以看作是相同操作,其实都已插入操作,只是位置的变化。

这时候想象一下,比如让你 e 插入 at 之前,但是只提供了,参数1插入参数2后面的操作,如何办到呢?

将 e 插入到 at 的前一个的后面,是不是就ok了,就相当于自己让别人插个队,你在我前面的后面站就行了

// Insert 插入:将 currentElement 插入至 originElement 后
func (list *List) Insert(currentElement, originElement *Element) *Element {
	currentElement.next = originElement.next
	currentElement.prev = originElement
	currentElement.prev.next = currentElement
	currentElement.next.prev = currentElement
	list.len++
	return currentElement
}
// InsertAfter 插入在之后
func (list *List) InsertAfter(currentElement, originElement *Element) *Element {
	return list.Insert(currentElement, originElement)
}
// InsertBefore 插入在之前
func (list *List) InsertBefore(currentElement, originElement *Element) *Element {
	return list.Insert(currentElement, originElement.prev)
}

这样一来,好像把 PushBack 和 PushFront都实现了,这就是封装的好处

// PushBack 插入一个元素在最后
func (list *List) PushBack(originElement *Element) *Element {
	list.InsertBefore(originElement, &list.root)
	return originElement
}
// PushFront 插入一个元素在最前
func (list *List) PushFront(originElement *Element) *Element {
	list.InsertAfter(originElement, &list.root)
	return originElement
}

Back & Front

这两个方式抽象上说,也是一样的功能,一个是返回链表最后一个,另一个是返回链表第一个,因为这里提供了头结点,所以特别简单

最后一个节点 = 头结点.prev

第一个节点 = 头结点.next

// Back 返回最后一个元素
func (list *List) Back() *Element {
	if list.len == 0 {
		return nil
	}
	// 头结点的上一个就是最后一个
	return list.root.prev
}
// Front 返回第一个元素
func (list *List) Front() *Element {
	if list.len == 0 {
		return nil
	}
	// 头结点的下一个就是第一个元素
	return list.root.next
}

Remove

Remove方法就是提供了,删除链表上的某个元素,怎么样才能删除某个节点呢,本质也就是让前后的节点相互链表,我就被排挤出来了,这样就可以实现删除

  • 将要删除的元素 e.next.prev = e.prev

  • 将要删除的元素 e.prev.next = e.next

// Remove 删除某个元素
func (list *List) Remove(originElement *Element) (any,error) {
	if originElement == &list.root {
		return nil, errors.New("the origin Element can not be list.root")
	}
	for e := list.root.next; e != &list.root; e = e.next {
		if e == originElement {
			e.prev.next = e.next
			e.next.prev = e.prev
			return e.Value, nil
		} else {
			continue
		}
	}
	return nil, errors.New("the origin Element dose not belong to the list")
}
阅读剩余 75%

原创文章,作者:DEGSR,如若转载,请注明出处:https://www.beidanyezhu.com/a/30979.html

(0)
DEGSR的头像DEGSR
上一篇 2025-02-23 17:29:08
下一篇 2025-02-23

相关推荐

  • 第7期(语言优美的句子)

    2022-03-12 星期六 虎 壬寅年 二月初十 【语录集锦】 亲情 满地都是金黄的梧桐叶,街上没有多少行人,你我走在回家的路上,只不过没有你,我想你了。 友情有一种朋友,距离再…

  • 爱孩子的五种语言(对儿女的爱的句子)

    查普曼博士提出了五种爱的语言——肯定的言辞、精心的时刻、接受礼物、服务的行动和身体的接触。这本书里主要是用于夫妻之间的爱语,其实家长和孩子的也是这样的五种爱语。 著名婚姻家庭专家盖…

  • 语言发育迟缓康复干货(语言发育迟缓怎么做康复训练)

    家有语言发育迟缓宝宝,最难的是什么吗? 语言发育迟缓宝宝训练有多难!最难的就是不能说话,不理解别人说话,早期发现时,多处于2-3岁,且行为能力有限,多数具有智力障碍和社交障碍,很多…

  • 语言(逅怎么读)

    引 言吴语是汉语族的一个重要分支,分布在江苏南部、浙江省大部、上海市全境,安徽南部及福建、江西的小部分地区。学术界将其分爲太湖片、台州片、东瓯片、婺州片、处衢片、宣州片六个小片。其…

  • 语言的谋略(洛邑怎么读)

    第十七辑 国家政策辩论的谋略与技巧文/钟百超 每个人对一定事物或做法都有自己的主见,而这个主见的形成与个人的信仰、理念、知识、修养,乃至利益都有密切相关。一个人能否提出一个有利于国…

  • Go语言中的next()方法怎么使用

    在许多编程语言中,序列是一种基本的数据结构。序列是有序的元素集合,并且序列中的元素可以通过索引访问。有时,在遍历序列时需要对序列中的每个元素一次进行操作。对于这种情况,就可以使用n…

  • Linux系统中怎么安装NSQ的Go语言客户端

    一、安装Go语言环境 在安装NSQ前,需先安装Go语言环境。在Linux系统中安装Go语言环境的步骤如下: 1.下载安装包官方网站https://golang.org/dl/提供了…

  • Go语言中怎么使用HTTPS协议进行请求

    一、简介 HTTPS是HTTP协议加密版,用于保护传输数据的安全。HTTPS协议基于TLS/SSL协议完成,其最新的版本是TLS1.3。在HTTPS协议下,服务器端的数字证书可以检…

  • 怎么在Go语言中隐藏窗口

    获取窗口句柄 在操作窗口之前,需要先获取窗口的句柄。在Windows平台上,每个窗口都有一个唯一的句柄用于标识该窗口。可以使用Windows API函数FindWindow或者Fi…

  • 怎么使用Go语言实现时间轮

    时间轮概述 时间轮是一种基于时间概念的循环缓冲区,可以将其视为一个圆形的缓冲区,其大小为m(2的幂次)。每次时间轮转动一个单位,例如1毫秒,所有缓冲区指向的内容也随之发生改变。在时…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

分享本页
返回顶部