单链表-Go语言实现

单链表

单链表;双链表;环形链表;

带头节点的单链表

head -> a1 -> a2 -> a3

有了头结点后,对在第一个元素结点前插入结点和删除第一个结点,其操作与对其它结点的操作统一了。

单链表的优缺点及使用场景

优点:

  • 插入删除操作便捷;
  • 不需要一块集中的内存空间;元素的存储单元是任意的,可连续也可不连续;
  • 不需要限定长度;

缺点:

  • 不支持随机存取,仅可以从头开始查找;其查找时间复杂度为O(n);
  • 存放元素时需要另外开辟一个指针域的空间;额外占用内存空间;

使用场景:

不清楚总体大小,且需要频繁的插入或删除操作;

节点结构

type LinkNode struct {
	Data interface{}	//Data使用接口,可以为任意类型,范性;
	Next *LinkNode
}

type LList LinkNode

实现接口
这里使用接口,写代码的时候忘了用了,直接用结构体的方法了;

type LLister interface {
	Creat_head()                  //头插法创建链表
	Creat_tail()                  //尾插法创建链表
	Insert(v interface{}, i int)  //插入v到第ige
	Delete(index int) interface{} //删除第i+1(i从0开始)个,返回value
	GetLength() int               //统计节点个数(不包括头节点)
	Search(v interface{}) int     //查找值为v的元素,返回所在位置
	Display()
}

创建单链表

  • 头插法:将新增节点插入到头节点之后;

    • 最先插入的在最后;读出链表是倒序;
    • head->9->8->7->6->5->4->3->2->1->0
    func (head *LList) Creat_head() {
    	for i := 0; i < 10; i++ {
    		s := &LinkNode{
    			Data: i,
    		}
    		s.Next = head.Next
    		head.Next = s
    	}
    }
    
  • 尾插法:“正常排队”

    • 先插入在最前
    • head->0->1->2->3->4->5->6->7->8->9
    func (head *LList) Creat_tail() {
    	p := head
    	for i := 0; i < 10; i++ {
    		s := &LinkNode{
    			Data: i,
    		}
    		p.Next = s
    		p = s
    	}
    }
    

单链表插入节点

这是有头节点的情况下,也就是头指针->头节点->第一个元素;

插入要明确插入规则,否则会乱掉;
在这里插入图片描述

在自己做练习时,没有特别要求时,确定好插入标准时必要的;

插入位置index,就相当于那个间隙,所以index可以是0~5(5个元素);

当index==length时,相当于尾抽;length==0时相当于头插;

  • 插入位置为index,先判断i是否合理;index < 0 || index > length
  • 移动p(p:=head)到插入位置;
  • 插入;
func (head *LList) Insert(v interface{}, index int) {
	length := head.GetLength()       //链表的长度,如3个就是3
	if index < 0 || index > length { //i=0时相当于头插法;i=length相当于尾插法;i=1时是在第一个节点之后插入
		fmt.Printf("index out of range %d\n", length)
		return
	}
	p := head
	for i := 0; i < index; i++ {
		p = p.Next
	}
	newNode := &LinkNode{Data: v}
	newNode.Next = p.Next
	p.Next = newNode
}

单链表删除

删除和插入类似,边界判断时稍有区别;
在这里插入图片描述

index=几就产出间隔后面的元素,比如index=0就删除a1,那么index不能为5,也就是边界条件:index < 0 || index >= length;

func (head *LList) Delete(index int) interface{} {
	length := head.GetLength()
	if index < 0 || index >= length {
		fmt.Printf("index out of range %d\n", length)
		return "index out of range, please check."
	}
	p := head
	for i := 0; i < index; i++ {
		p = p.Next
	}
	deleteNode := p.Next
	p.Next = p.Next.Next
	return deleteNode.Data
}

单链表完整代码

package main

import (
	"fmt"
)

type LinkNode struct {
	Data interface{}
	Next *LinkNode
}

type LList = LinkNode

type LLister interface {
	Creat_head()                  //头插法创建链表
	Creat_tail()                  //尾插法创建链表
	Insert(v interface{}, i int)  //插入v到第ige
	Delete(index int) interface{} //删除第i+1(i从0开始)个,返回value
	GetLength() int               //统计节点个数(不包括头节点)
	Search(v interface{}) int     //查找值为v的元素,返回所在位置
	Display()
}

func newLList() *LList {
	return &LList{Next: nil}
}

func (head *LList) Creat_head() {
	for i := 0; i < 10; i++ {
		s := &LinkNode{
			Data: i,
		}
		s.Next = head.Next
		head.Next = s
	}
}

func (head *LList) Creat_tail() {
	p := head
	for i := 0; i < 10; i++ {
		s := &LinkNode{
			Data: i,
		}
		p.Next = s
		p = s
	}
}

func (head *LList) Insert(v interface{}, index int) {
	length := head.GetLength()       //链表的长度,如3个就是3
	if index < 0 || index > length { //i=0时相当于头插法;i=length相当于尾插法;i=1时是在第一个节点之后插入
		fmt.Printf("index out of range %d\n", length)
		return
	}
	p := head
	for i := 0; i < index; i++ {
		p = p.Next
	}
	newNode := &LinkNode{Data: v}
	newNode.Next = p.Next
	p.Next = newNode
}

func (head *LList) Delete(index int) interface{} {
	length := head.GetLength()
	if index < 0 || index >= length {
		fmt.Printf("index out of range %d\n", length)
		return "index out of range, please check."
	}
	p := head
	for i := 0; i < index; i++ {
		p = p.Next
	}
	deleteNode := p.Next
	p.Next = p.Next.Next
	return deleteNode.Data
}

func (head *LList) GetLength() int {
	p := head.Next
	var length int = 0
	for p != nil {
		length++
		p = p.Next
	}
	return length
}

func (head *LList) Search(value int) interface{} {
	p := head.Next
	index := 1
	for p != nil {
		if p.Data == value {
			return index
		}
		index++
		p = p.Next
	}
	return fmt.Sprintf("the value %v is not in the llist;", value)
}

func (head *LList) Display() {
	p := head.Next
	fmt.Print("head")
	for p != nil {
		fmt.Printf("->%v", p.Data)
		p = p.Next
	}
	fmt.Println()
}

func main() {
	head := newLList()
	head.Creat_tail()
	head.Display()
	head.Insert(99, 10)
	head.Display()
	result := head.Search(99)
	fmt.Printf("search result is: %v\n", result)
	deleteValue := head.Delete(10)
	fmt.Printf("delete node value is %v\n", deleteValue)
	head.Display()
	fmt.Printf("link list length is: %v", head.GetLength())
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值