Go实现单链表(并发不安全)

Go数据结构:单链表

    • 单链表的特点
    • 单链表的结构
    • 前插代码的实现
    • 后插代码的实现
    • 在指定位置插入元素
    • 在指定位置删除元素
    • 删除指定元素的第一个元素
    • 删除所有指定元素
    • 查找是否包含该值
    • 遍历单链表
    • 全部代码

单链表的特点

  每个节点包含两个域:数据域和指针域。数据域存储数据元素,指针域存储下一个节点的地址。
  单链表的物理存储空间可以是不连续的,它通过指针域来表示数据元素之间的逻辑关系。
  单链表有一个头指针,它指向链表的第一个节点。有时也会有一个头节点,它是一个不存储数据的空节点,方便链表的操作。
单链表的尾节点的指针域为空,表示链表的结束。
  单链表的插入和删除操作只需要修改指针域,时间复杂度为O(1)。但是查找操作需要从头指针开始遍历,时间复杂度为O(n)。
   下一章节将会更新并发安全的单链表

单链表的结构

  一共创建了两个结构体,Node 创建的是节点,List 创建的才是真正的链表,它储存的有节点以及他的节点长度

type Node struct {
	Data     any
	NodeNext *Node
}
type List struct {
	length   int //储存链表的长度
	headNode *Node
}
func NewLinkList() *List {
	node := new(Node)
	return &List{
		headNode: node,
	}
}

前插代码的实现

  我们添加元素的时候,肯定要先创建一个空节点,然后判断其节点的长度是否为0,如果为零就把插入的元素添加到data中,如果不为零,创建一个node节点,把元素添加到node节点的data中,然后把根节点的元素指向node节点中的headNode 中,这样node就成了根节点了,然后在把根节点的地址指向链表。
  简单来讲就是子节点先添加元素,然后Node地址指向根节点,这样子节点就是根节点了,最开始插入的元素在最后

// AddElemForward 前插元素
func (l *List) AddElemForward(data any) {
	node := &Node{Data: data}
	if l.IsNull() {
		l.headNode = node
		l.length++
		return
	}
	node.NodeNext = l.headNode
	l.headNode = node
	l.length++
	return
}
func (l *List) IsNull() bool {
	if l.length == 0 {
		return true
	} else {
		return false
	}
}

后插代码的实现

  添加第一个元素和前插的逻辑一样,后插插入元素,要先遍历节点,直到最后一个节点为nil位置,然后在把当前节点的next指向node

// AppendElemBack 后插元素
func (l *List) AppendElemBack(data any) {
	node := &Node{Data: data}
	if l.IsNull() {
		l.headNode = node
		l.length++
		return
	}
	cur := l.headNode
	for cur.NodeNext != nil {
		cur = cur.NodeNext
	}
	cur.NodeNext = node
	l.length++
}

在指定位置插入元素

  在指定位置插入的时候,我们要先判断异常情况,就是插入的指针一定要在节点长度的范围内,当插入的指针为1的时候也是特殊情况,他并不需要遍历,直接把根节点指向node的next,然后再把node指向根节点即可。但是这是前插。简单点来讲就是先找到插入节点的位置,然后把插入节点的后面所有元素指向node.next,再把node指向插入节点的next

// InsertForwardElem 指定位置插入
func (l *List) InsertForwardElem(index int, elem any) {
	if l.length < index+1 || index <= 0 {
		fmt.Println("插入的index错误,请重新输入")
	}
	pre := l.headNode
	node := &Node{Data: elem}
	if index == 1 {
		node.NodeNext = pre
		l.headNode = node
		return
	}
	for count := 1; count < index; count++ {
		pre = pre.NodeNext
	}
	node.NodeNext = pre.NodeNext
	pre.NodeNext = node
	l.length++
}

在指定位置删除元素

   和插入的逻辑差不多,我就不在赘述,简单来讲就是先查询到要删除的前一个节点,然后把这个节点的下一个的下一个节点指向它,这就把删除的节点给绕开了

// DeleteForwardElem 删除指定位置的元素
func (l *List) DeleteForwardElem(index int) {
	if l.length < index+1 || index <= 0 {
		fmt.Println("插入的index错误,请重新输入")
	}
	pre := l.headNode
	if index == 1 {
		l.headNode = pre.NodeNext.NodeNext
	}
	for count := 1; count < index; count++ {
		pre = pre.NodeNext
	}
	pre.NodeNext = pre.NodeNext.NodeNext
}

删除指定元素的第一个元素

下面代码实现的删除第一个元素,我会重点讲解删除所有元素

// RemoveElem 删除节点中第一个指定元素
func (l *List) RemoveElem(data any) {
	pre := l.headNode
	index := 0
	if pre.Data == data {
		l.headNode = pre.NodeNext
		fmt.Println("ok")
	}
	for pre != nil {
		index++
		if pre.NodeNext.Data == data {
			pre.NodeNext = pre.NodeNext.NodeNext
			fmt.Println("ok")
			l.length--
			return
		}
		pre = pre.NodeNext
	}
	fmt.Println("fail")
}

删除所有指定元素

   删除所有元素的逻辑有点复杂,当我们删除元素时、,一定是要知道删除元素的前节点和后节点,因为单链表就没有双向指针,所以就要先知道前节点,在通过前节点知道删除节点和后续节点,设计思路就是一直遍历链表,看他的元素是否和我们想要删除的元素是否相同,如果相同就删除,不相同就把指针指向下个节点,但是这样就会有一个问题,如果我们要删除的下下个节点也是我们要删除的呢?这样会导致一个问题,就是如果下下个节点也相同,我们就不能删除他,因为单链表没有双向指针,所以遇到连续要删除的元素就要在加一个for,把所有连续的元素全部删完,在进行下一步的逻辑。具体逻辑可以自己好好琢磨。

// RemoveElemAll 删除所有元素
func (l *List) RemoveElemAll(data any) {
	pre := l.headNode
	if pre.Data == data {
		l.headNode = pre.NodeNext
		l.length--
		fmt.Println("ok")
	}
	for pre.NodeNext != nil {
		if pre.NodeNext.Data == data {
			pre.NodeNext = pre.NodeNext.NodeNext
			fmt.Println("ok")
			l.length--
			if pre.NodeNext != nil {
				for pre.NodeNext.Data == data {
					pre.NodeNext = pre.NodeNext.NodeNext
					fmt.Println("ok")
					l.length--

					if pre.Data != data {
						break
					}
					if pre == nil {
						return
					}
					pre = pre.NodeNext
				}
			}
		}
		pre = pre.NodeNext
		if pre == nil {
			return
		}
	}
}

查找是否包含该值

// SearchElem 查找是否包含指定值
func (l *List) SearchElem(data any) bool {
	/*单链表的按值查找
	  1、用指针p指向首元结点
	  2、从首元结点开始以此顺着链域next向下查找,只要指向当前结点的指针p不为空,
	  并且p所指结点的数据域不等于给定值e,则执行以下操作:p指向下一个结点
	  3、返回p。若查找成功,p此时即为结点的地址值,若查找失败,p的值即为NULL。
	*/
	if l.IsNull() {
		fmt.Println("err")
	}
	pre := l.headNode
	for pre != nil {
		if pre.Data == data {
			return true
		}
		pre = pre.NodeNext
	}
	return false

}

遍历单链表

func (l *List) ShowList() {
	if !l.IsNull() {
		cur := l.headNode
		for {
			fmt.Printf("\t%v", cur.Data)
			if cur.NodeNext != nil {
				cur = cur.NodeNext
			} else {
				break
			}
		}
	}
}

全部代码

package main

import (
	"fmt"
)

type Node struct {
	Data     any
	NodeNext *Node
}

type List struct {
	length   int //储存链表的长度
	headNode *Node
}

// insert data

func NewLinkList() *List {
	node := new(Node)
	return &List{
		headNode: node,
	}
}

// InsertForwardElem 指定位置插入
func (l *List) InsertForwardElem(index int, elem any) {
	if l.length < index+1 || index <= 0 {
		fmt.Println("插入的index错误,请重新输入")
	}
	pre := l.headNode
	node := &Node{Data: elem}
	if index == 1 {
		node.NodeNext = pre
		l.headNode = node
		return
	}
	for count := 1; count < index; count++ {
		pre = pre.NodeNext
	}
	node.NodeNext = pre.NodeNext
	pre.NodeNext = node
	l.length++
}

// DeleteForwardElem 删除指定位置的元素
func (l *List) DeleteForwardElem(index int) {
	if l.length < index+1 || index <= 0 {
		fmt.Println("插入的index错误,请重新输入")
		return
	}
	pre := l.headNode
	if index == 1 {
		l.headNode = pre.NodeNext.NodeNext
	}
	for count := 1; count < index; count++ {
		pre = pre.NodeNext
	}
	pre.NodeNext = pre.NodeNext.NodeNext
	l.length--
	fmt.Println("success deleted")
}

// RemoveElem 删除节点中第一个指定元素
func (l *List) RemoveElem(data any) {
	pre := l.headNode
	index := 0
	if pre.Data == data {
		l.headNode = pre.NodeNext
		fmt.Println("ok")
	}
	for pre != nil {
		index++
		if pre.NodeNext.Data == data {
			pre.NodeNext = pre.NodeNext.NodeNext
			fmt.Println("ok")
			l.length--
			return
		}
		pre = pre.NodeNext
	}
	fmt.Println("fail")
}

// RemoveElemAll 删除所有元素
func (l *List) RemoveElemAll(data any) {
	pre := l.headNode
	if pre.Data == data {
		l.headNode = pre.NodeNext
		l.length--
		fmt.Println("ok")
	}
	for pre.NodeNext != nil {
		if pre.NodeNext.Data == data {
			pre.NodeNext = pre.NodeNext.NodeNext
			fmt.Println("ok")
			l.length--
			if pre.NodeNext != nil {
				for pre.NodeNext.Data == data {
					pre.NodeNext = pre.NodeNext.NodeNext
					fmt.Println("ok")
					l.length--

					if pre.Data != data {
						break
					}
					if pre == nil {
						return
					}
					pre = pre.NodeNext
				}
			}
		}
		pre = pre.NodeNext
		if pre == nil {
			return
		}
	}
}

// AddElemForward 前插元素
func (l *List) AddElemForward(data any) {
	node := &Node{Data: data}
	if l.IsNull() {
		l.headNode = node
		l.length++
		return
	}
	node.NodeNext = l.headNode
	l.headNode = node
	l.length++
	return
}

// AppendElemBack 后插元素
func (l *List) AppendElemBack(data any) {
	node := &Node{Data: data}
	if l.IsNull() {
		l.headNode = node
		l.length++
		return
	}
	cur := l.headNode
	for cur.NodeNext != nil {
		cur = cur.NodeNext
	}
	cur.NodeNext = node
	l.length++
}

func (n *Node) Search() {
	for {
		if n.NodeNext != nil {
			fmt.Println(n.Data)
		}
		break
	}
}
func (l *List) IsNull() bool {
	if l.length == 0 {
		return true
	} else {
		return false
	}
}
func (l *List) ShowList() {
	if !l.IsNull() {
		cur := l.headNode
		for {
			fmt.Printf("\t%v", cur.Data)
			if cur.NodeNext != nil {
				cur = cur.NodeNext
			} else {
				break
			}
		}
	}
}

// SearchElem 查找是否包含指定值
func (l *List) SearchElem(data any) bool {
	/*单链表的按值查找
	  1、用指针p指向首元结点
	  2、从首元结点开始以此顺着链域next向下查找,只要指向当前结点的指针p不为空,
	  并且p所指结点的数据域不等于给定值e,则执行以下操作:p指向下一个结点
	  3、返回p。若查找成功,p此时即为结点的地址值,若查找失败,p的值即为NULL。
	*/
	if l.IsNull() {
		fmt.Println("err")
	}
	pre := l.headNode
	for pre != nil {
		if pre.Data == data {
			return true
		}
		pre = pre.NodeNext
	}
	return false

}
func main() {
	Link := NewLinkList()
	Link.AppendElemBack(3)
	Link.AppendElemBack(4)
	Link.AppendElemBack("5")
	Link.AppendElemBack(5)
	Link.AppendElemBack(553)
	Link.AppendElemBack(5)
	Link.AppendElemBack(5)
	Link.AppendElemBack(553)
	Link.AppendElemBack(5)
	Link.RemoveElemAll(5)
	Link.ShowList()
	Link.InsertForwardElem(2, 8)
	Link.ShowList()
}

你可能感兴趣的:(golang,开发语言,后端)