Go-如何优雅的实现单链表?(含全部代码)_go listnode len,2024年最新重难点整理

30 阅读3分钟

为了能够兼容所有类型,采用空接口。为了更好的封装,用"私有"的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)

测试

常见问题

img img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!