每个节点包含两个域:数据域和指针域。数据域存储数据元素,指针域存储下一个节点的地址。
单链表的物理存储空间可以是不连续的,它通过指针域来表示数据元素之间的逻辑关系。
单链表有一个头指针,它指向链表的第一个节点。有时也会有一个头节点,它是一个不存储数据的空节点,方便链表的操作。
单链表的尾节点的指针域为空,表示链表的结束。
单链表的插入和删除操作只需要修改指针域,时间复杂度为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()
}