单链表-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())
}