Go-如何优雅的实现单链表?(含全部代码)

Posted lady_killer9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go-如何优雅的实现单链表?(含全部代码)相关的知识,希望对你有一定的参考价值。

目录

简介

思路

节点结构体

属性

方法

单链表结构体

属性

方法

Init

New

Clear

Len

Front

Back

insert

InsertAfter

PushBack

PushFront

remove

RemoveAfter

RemoveFront

测试

常见问题

怎么遍历呀?

全部代码


简介

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成是元素加指针。

思路

为了能够兼容所有类型,采用空接口。为了更好的封装,用"私有"的next和insert、remove等,看下方详细解释。

节点结构体

属性

type ListNode struct {
    Val interface{}
    next *ListNode
    lst *SingleList
}
  • Val:节点的值
  • next:下一节点指针
  • lst:所属单链表

Val采用空接口,接收任意数据类型,可通过类型断言再赋给对应类型。

方法

返回下一个节点,O(1)

func (node *ListNode)Next() *ListNode {
	return node.next
}

主要用于遍历,我在其他方法中也有调用。

单链表结构体

属性

type SingleList struct {
	head *ListNode
	len int
}
  • head:头结点
  • len:单链表长度

这里其实可以将head的Val用来存储长度,可以稍微节省一点内存,由于还需要类型断言,比较麻烦,就算了

方法

Init

func (lst *SingleList)Init(){
	lst.head = new(ListNode)
	lst.head.lst = lst
	lst.len = 0
}

创建头结点,长度为0,O(1)

New

func New() *SingleList {
	lst := new(SingleList)
	lst.Init()
	return lst
}

返回创建的单链表,调用了Init,O(1)

Clear

func (lst *SingleList)Clear(){
	lst.Init()
}

调用Init,利用Go自己的垃圾回收,O(1)

Len

func (lst *SingleList)Len() int {
	return lst.len
}

返回单链表长度,O(1)

Front

func (lst *SingleList)Front() *ListNode {
	return lst.head.Next()
}

返回第一个节点,就是头结点的下一个节点,空链表情况下为nil,O(1)

Back

func (lst *SingleList)Back() *ListNode {
	if lst.len == 0{
		return nil
	}
	cur := lst.head.Next()
	for{
		if cur.Next() == nil{
			return cur
		}
		cur = cur.Next()
	}
}

返回最后一个节点,空链表的情况下为nil,O(n)

insert

func (lst *SingleList)insert(e, at *ListNode) *ListNode{
	lst.len++
	e.next = at.next
	at.next = e
	e.lst = lst
	return e
}

返回指向插入的节点e的指针。

  • e:待插入节点
  • at:链表

仅在此函数进行长度增加,其他插入函数调用此函数,O(1)。

InsertAfter

func (lst *SingleList)InsertAfter(val interface{}, mark *ListNode) *ListNode {
	if mark == nil{
		return nil
	}
	if mark.lst == lst{
		return lst.insert(&ListNode{Val:val},mark)
	}
	return nil
}

生成值为val的节点,并插入链表节点mark后,返回插入的节点,mark为nil或不属于单链表的情况下,返回nil。调用了insert,O(1)

  • val:待插节点值
  • mark:在此节点后插入,如果此节点属于单链表lst

PushBack

func (lst *SingleList)PushBack(val interface{}) *ListNode{
	end := lst.Back()
	if end == nil{
		return lst.InsertAfter(val,lst.head)
	}else {
		return lst.InsertAfter(val,end)
	}
}

生成值为val的节点,并插入链表尾节点后,调用Back和InsertAfter。返回指向生成节点的指针,O(n)。

  • val:待插节点值

PushFront

func (lst *SingleList)PushFront(val interface{}) *ListNode {
	return lst.InsertAfter(val,lst.head)
}

 生成值为val的节点,并插入链表头节点后,调用InsertAfter。返回指向生成节点的指针,O(1)。

  • val:待插节点值

remove

func (lst *SingleList)remove(e *ListNode) *ListNode{
	nextOne := e.next
	if nextOne == nil{
		return nil
	}
	lst.len--
	e.next = e.next.next
	nextOne.lst = nil
	return nextOne
}

 删除e的下一个节点,返回删除的节点,仅在此函数进行长度减少,其他删除函数调用此函数。e是尾节点时返回nil,O(1)。

  • e:单链表上的节点,需删除它后面的一个节点

RemoveAfter

func (lst *SingleList)RemoveAfter(e *ListNode) *ListNode{
	if e == nil{
		return nil
	}
	if e.lst == lst{
		return lst.remove(e)
	}
	return nil
}

删除指定节点的后一个节点,返回删除的节点,指定元素为尾节点或nil时,返回nil,O(1)

RemoveFront

func (lst *SingleList)RemoveFront() *ListNode {
	return lst.remove(lst.head)
}

前删,删除第一个节点,返回删除的节点,可能为nil,O(1)

测试

常见问题

怎么遍历呀?

像下面这样就可以了呦

for e := lst.Front(); e != nil; e = e.Next() {
   do something with e.Val
}

全部代码

具体代码和测试代码在:https://gitee.com/frankyu365/datastructure

参考

Go标准库-container/list

更多Go相关内容:Go-Golang学习总结笔记

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。

以上是关于Go-如何优雅的实现单链表?(含全部代码)的主要内容,如果未能解决你的问题,请参考以下文章

基本数据结构实现--单链表含测试代码

Go-动态类型与类型断言详解(含type-switch及全部代码)

php与go实现单链表对比

单链表python和go的代码

go web感受一下go语言的代码简洁与优雅

单链表的创建插入删除遍历的Go实现