脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Go 语言结构体链表的基本操作

Go 语言结构体链表的基本操作

2022-09-25 12:02隐姓埋名4869 Golang

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,这篇文章主要介绍了Go 语言结构体链表,需要的朋友可以参考下

1. 什么是链表

  • 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
  • 链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
  • 使用链表结构可以避免在使用数组时需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
  • 链表允许插入和移除表上任意位置上的结点,但是不允许随机存取。
  • 链表有三种类型:单向链表双向链表循环链表

2. 单项链表的基本操作

  • 单向链表中每个结点包含两部分,分别是数据域指针域,上一个结点的指针指向下一结点,依次相连,形成链表。
  • 链表通过指针将一组零散的内存块串联在一起,这里的内存块称为链表的结点。为了将这些节点给串起来,每个链表的结点除了存储数据之外,还会记录下一个结点的指针(即下一个结点的地址),这个指针称为:后继指针

Go 语言结构体链表的基本操作

3. 使用 struct 定义单链表

  • 利用 Struct 可以包容多种数据类型的特性
  • 一个结构体内可以包含若干成员,这些成员可以是基本类型、自定义类型、数组类型,也可以是指针类型。

struct 定义的三种形式,其中2和3都是返回结构体的指针

?
1
2
3
4
5
6
7
8
9
10
11
//定义
var stu Student
 
var stu *Student = new(Student)
 
var stu *Student = &Student {}
 
//调用
stu.Name   stu.Age    stu.Score
(*stu).Name    (*stu).Age   (*stu).Score

定义一个单项链表
next 是指针类型的属性,指向 Student struct 类型数据,也就是下一个节点的数据类型

?
1
2
3
4
5
6
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student
}

为链表赋值,并遍历链表中的每个节点

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main
import "fmt"
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student      //存放下一个结构体的地址,用*直接指向下一个结构体
}
func main() {
    //头部结构体
    var head Student
    head.Name = "张三"
    head.Age = 28
    head.Score = 88
    //第二个结构体节点
    var stu1 Student
    stu1.Name = "李四"
    stu1.Age = 25
    stu1.Score = 100
    head.next = &stu1
    //第三个结构体节点
    var stu2 Student
    stu2.Name = "王五"
    stu2.Age = 18
    stu2.Score = 60
    stu1.next = &stu2
    Req(&head)
}
func Req(tmp *Student) {        //tmp指针是指向下一个结构体的地址,加*就是下一个结构体
    for tmp != nil {            //遍历输出链表中每个结构体,判断是否为空
        fmt.Println(*tmp)
        tmp = tmp.next          //tmp变更为下一个结构体地址
    }
}

//输出结果如下
{张三 28 88 0xc000114480}
{李四 25 100 0xc0001144b0}
{王五 18 60 <nil>}

4. 尾部添加节点方法一

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package main
import (
    "fmt"
    "math/rand"
)
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student
}
func main() {
    //头部结构体
    var head Student
    head.Name = "head"
    head.Age = 28
    head.Score = 88
    //第二个结构体节点
    var stu1 Student
    stu1.Name = "stu1"
    stu1.Age = 25
    stu1.Score = 100
    head.next = &stu1 //头部指向第一个结构体
    //第三个结构体节点
    var stu2 Student
    stu2.Name = "stu2"
    stu2.Age = 18
    stu2.Score = 60
    stu1.next = &stu2 //第一个结构体指向第二个结构体
    //第四个结构体节点
    var stu3 Student
    stu3.Name = "stu3"
    stu3.Age = 18
    stu3.Score = 80
    stu2.next = &stu3 //第二个结构体指向第三个结构体
    //声明变量
    var tail = &stu3
    for i := 4; i < 10; i++ {
        //定义节点
        var stu Student = Student{
            Name:  fmt.Sprintf("stu%d", i),
            Age:   rand.Intn(100),
            Score: rand.Float32() * 100,
        }
        //生产结构体串联
        tail.next = &stu
        tail = &stu
    }
    Req(&head)
}
func Req(tmp *Student) {
    for tmp != nil {
        fmt.Println(*tmp)
        tmp = tmp.next
    }
}

//输出结果如下
{head 28 88 0xc0001144b0}
{stu1 25 100 0xc0001144e0}
{stu2 18 60 0xc000114510}
{stu3 18 80 0xc000114540}
{stu4 81 94.05091 0xc000114570}
{stu5 47 43.77142 0xc0001145a0}
{stu6 81 68.682304 0xc0001145d0}
{stu7 25 15.651925 0xc000114600}
{stu8 56 30.091187 0xc000114630}
{stu9 94 81.36399 <nil>}

方法二,使用函数进行优化

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main
import (
    "fmt"
    "math/rand"
)
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student
}
func main() {
    //头部结构体
    var head Student
    head.Name = "head"
    head.Age = 28
    head.Score = 88
    TailInsert(&head)
    Req(&head)
}
//循环遍历
func Req(tmp *Student) {
    for tmp != nil {
        fmt.Println(*tmp)
        tmp = tmp.next
    }
}
//添加结构体节点
func TailInsert(tail *Student) {
    for i := 0; i < 10; i++ {
        //定义节点
        var stu Student = Student{
            Name:  fmt.Sprintf("stu%d", i),
            Age:   rand.Intn(100),
            Score: rand.Float32() * 100,
        }
        //生产结构体串联
        tail.next = &stu    //指向下一个结构体
        tail = &stu         //把当前的结构体给tail,让其继续循环
    }
}

//输出结果如下
{head 28 88 0xc0001144b0}
{stu0 81 94.05091 0xc0001144e0}
{stu1 47 43.77142 0xc000114510}
{stu2 81 68.682304 0xc000114540}
{stu3 25 15.651925 0xc000114570}
{stu4 56 30.091187 0xc0001145a0}
{stu5 94 81.36399 0xc0001145d0}
{stu6 62 38.06572 0xc000114600}
{stu7 28 46.888985 0xc000114630}
{stu8 11 29.310184 0xc000114660}
{stu9 37 21.855305 <nil>}

5. 头部插入节点方法一

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main
 
import (
    "fmt"
    "math/rand"
)
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student
}
func main() {
    //头部结构体
    var head Student
    head.Name = "head"
    head.Age = 28
    head.Score = 88
    //调用头部插入函数
    HeadInsert(&head)
    Req(HeadInsert(&head))
func Req(tmp *Student) {
    for tmp != nil {
        fmt.Println(*tmp)
        tmp = tmp.next
    }
func HeadInsert(p *Student) *Student {
    for i := 0; i < 10; i++ {
        var stu = Student{
            Name:  fmt.Sprintf("stu%d", i),
            Age:   rand.Intn(100),
            Score: rand.Float32() * 100,
        }
        //当前新节点指向head,因为head是下一个节点
        stu.next = p //指向下一个节点
        p = &stu     //把当前的结构体给tail,让其继续循环
    return p

//输出结果如下
{stu9 85 30.152267 0xc000094840}
{stu8 37 5.912065 0xc000094810}
{stu7 29 7.9453626 0xc0000947e0}
{stu6 87 60.72534 0xc0000947b0}
{stu5 41 2.8303082 0xc000094780}
{stu4 90 69.67192 0xc000094750}
{stu3 87 20.658266 0xc000094720}
{stu2 47 29.708258 0xc0000946f0}
{stu1 28 86.249146 0xc0000946c0}
{stu0 95 36.08714 0xc0000944b0}
{head 28 88 <nil>}

Go 语言结构体链表的基本操作

方法二

使用指针的指针

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main
 
import (
    "fmt"
    "math/rand"
)
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student
}
func main() {
    //头部结构体
    var head *Student = &Student{}
    head.Name = "head"
    head.Age = 28
    head.Score = 88
    //调用头部插入函数
    HeadInsert(&head)
    Req(head)
func Req(tmp *Student) {
    for tmp != nil {
        fmt.Println(*tmp)
        tmp = tmp.next
    }
func HeadInsert(p **Student) {
    for i := 0; i < 10; i++ {
        var stu = Student{
            Name:  fmt.Sprintf("stu%d", i),
            Age:   rand.Intn(100),
            Score: rand.Float32() * 100,
        }
        //当前新节点指向head,因为head是下一个节点
        stu.next = *p //指向下一个节点
        *p = &stu     //把当前的结构体给tail,让其继续循环

//输出结果如下
{stu9 37 21.855305 0xc000114660}
{stu8 11 29.310184 0xc000114630}
{stu7 28 46.888985 0xc000114600}
{stu6 62 38.06572 0xc0001145d0}
{stu5 94 81.36399 0xc0001145a0}
{stu4 56 30.091187 0xc000114570}
{stu3 25 15.651925 0xc000114540}
{stu2 81 68.682304 0xc000114510}
{stu1 47 43.77142 0xc0001144e0}
{stu0 81 94.05091 0xc0001144b0}
{head 28 88 <nil>}

总结
如果想要外部的数据和函数处理结果进行同步,两种方法:
① 传参,传递指针
② return 进行值的返回

6. 指定节点后添加新节点

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main
 
import (
    "fmt"
    "math/rand"
)
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student
}
func main() {
    //头部结构体
    var head *Student = &Student{} //定义指针类型
    head.Name = "head"
    head.Age = 28
    head.Score = 88
    //定义新的节点
    var newNode *Student = &Student{} //定义指针类型
    newNode.Name = "newNode"
    newNode.Age = 19
    newNode.Score = 78
    HeadInsert(&head)
    //指定位置插入函数
    Add(head, newNode)
    Req(head)
func Req(tmp *Student) {
    for tmp != nil {
        fmt.Println(*tmp)
        tmp = tmp.next
    }
func HeadInsert(p **Student) { //传入指针的指针
    for i := 0; i < 10; i++ {
        var stu = Student{
            Name:  fmt.Sprintf("stu%d", i),
            Age:   rand.Intn(100),
            Score: rand.Float32() * 100,
        }
        //当前新节点指向head,因为head是下一个节点
        stu.next = *p //指向下一个节点
        *p = &stu     //把当前的结构体给tail,让其继续循环
//p为当前节点,newnode为插入的节点
func Add(p *Student, newNode *Student) {
    for p != nil {
        if p.Name == "stu6" {
            //对接下一个节点
            newNode.next = p.next
            p.next = newNode
        //插入节点指向下一个节点
        p = p.next //p.next赋予给p,继续进行循环遍历

//输出结果如下
{stu9 37 21.855305 0xc0000c0660}
{stu8 11 29.310184 0xc0000c0630}
{stu7 28 46.888985 0xc0000c0600}
{stu6 62 38.06572 0xc0000c04b0}
{newNode 19 78 0xc0000c05d0}
{stu5 94 81.36399 0xc0000c05a0}
{stu4 56 30.091187 0xc0000c0570}
{stu3 25 15.651925 0xc0000c0540}
{stu2 81 68.682304 0xc0000c0510}
{stu1 47 43.77142 0xc0000c04e0}
{stu0 81 94.05091 0xc0000c0480}
{head 28 88 <nil>}

7. 删除节点

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package main
 
import (
    "fmt"
    "math/rand"
)
type Student struct {
    Name  string
    Age   int
    Score float32
    next  *Student
}
func main() {
    //头部结构体
    var head *Student = &Student{} //定义指针类型
    head.Name = "head"
    head.Age = 28
    head.Score = 88
    //定义新的节点
    var newNode *Student = &Student{} //定义指针类型
    newNode.Name = "newNode"
    newNode.Age = 19
    newNode.Score = 78
    HeadInsert(&head)
    //指定位置插入函数
    Add(head, newNode)
    //删除节点
    del(head)
    Req(head)
func Req(tmp *Student) {
    for tmp != nil {
        fmt.Println(*tmp)
        tmp = tmp.next
    }
func HeadInsert(p **Student) { //传入指针的指针
    for i := 0; i < 10; i++ {
        var stu = Student{
            Name:  fmt.Sprintf("stu%d", i),
            Age:   rand.Intn(100),
            Score: rand.Float32() * 100,
        }
        //当前新节点指向head,因为head是下一个节点
        stu.next = *p //指向下一个节点
        *p = &stu     //把当前的结构体给tail,让其继续循环
//p为当前节点,newnode为插入的节点
func Add(p *Student, newNode *Student) {
    for p != nil {
        if p.Name == "stu6" {
            //对接下一个节点
            newNode.next = p.next
            p.next = newNode
        //插入节点指向下一个节点
        p = p.next //p.next赋予给p,继续进行循环遍历
//删除节点
func del(p *Student) {
    var prev *Student = p           //p=head   prev=head  ——》prev=p
        if p.Name == "newNode" {
            prev.next = p.next
            break
        prev = p            //进行平移,前节点赋值
        p = p.next          //后节点赋值

 //输出结果如下
 {stu9 37 21.855305 0xc0000c0660}
{stu8 11 29.310184 0xc0000c0630}
{stu7 28 46.888985 0xc0000c0600}
{stu6 62 38.06572 0xc0000c05d0}
{stu5 94 81.36399 0xc0000c05a0}
{stu4 56 30.091187 0xc0000c0570}
{stu3 25 15.651925 0xc0000c0540}
{stu2 81 68.682304 0xc0000c0510}
{stu1 47 43.77142 0xc0000c04e0}
{stu0 81 94.05091 0xc0000c0480}
{head 28 88 <nil>}

到此这篇关于Go 语言结构体链表的文章就介绍到这了,更多相关Go 语言结构体链表内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/lvrui/p/16163121.html

延伸 · 阅读

精彩推荐
  • Golang一篇文章教会你如何使用Go语言Modules

    一篇文章教会你如何使用Go语言Modules

    go moudules是Go的一个包管理工具,官方提供的,还是比较靠谱的,最低Go版本要求1.11+。...

    Go语言进阶学习11442021-09-15
  • GolangGo语言中并发的工作原理

    Go语言中并发的工作原理

    本文详细讲解了Go语言中并发的工作原理,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...

    奋斗的大橙子8902022-07-16
  • Golang关于Golang变量初始化/类型推断/短声明的问题

    关于Golang变量初始化/类型推断/短声明的问题

    这篇文章主要介绍了关于Golang变量初始化/类型推断/短声明的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友...

    nbody19968972021-03-28
  • Golanggolang将多路复异步io转成阻塞io的方法详解

    golang将多路复异步io转成阻塞io的方法详解

    常见的IO模型有阻塞、非阻塞、IO多路复用,异,下面这篇文章主要给大家介绍了关于golang将多路复异步io转成阻塞io的方法,文中给出了详细的示例代码,...

    D_Guco3202020-05-09
  • Golang解决golang 关于全局变量的坑

    解决golang 关于全局变量的坑

    这篇文章主要介绍了解决golang 关于全局变量的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    浪_沏沙12472021-06-22
  • Golanggolang等待触发事件的实例

    golang等待触发事件的实例

    这篇文章主要介绍了golang等待触发事件的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    思维的深度4172021-03-18
  • Golanggo实现脚本解释器gscript

    go实现脚本解释器gscript

    这篇文章主要为大家介绍了go实现脚本解释器gscript示例代码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    crossoverJie's7242022-07-14
  • Golang解决Golang 中使用WaitGroup的那点坑

    解决Golang 中使用WaitGroup的那点坑

    这篇文章主要介绍了解决Golang 中使用WaitGroup的那点坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    he_silong6792021-06-03