Go语言-结构体链表

目录

前言

1、定义struct的三种方式

2、存储方式

3、链表更新

4、头部添加结构体

5、指定位置插入

6、删除节点


前言

结构体是自定义复杂的数据结构,struck里面可以包含多个字段(属性),struck类型可以定义方法,和函数有区分,struck属于值类型,且可以做嵌套,Go中没有Class类型,只有struck类型。

1、定义struct的三种方式

格式方式:

1:var struct Student
2:var struct *Student = new (Student)
3:var struct *Student = &Student {}

示例:

package main

import "fmt"

//结构体定义
type Student struct {
	Name  string
	Age   int
	Score float32
	next  *Student
}

func main() {

	//实体1
	//第一种方式定义
	var head Student
	head.Name = "head"
	head.Age = 20
	head.Score = 80

	//实体2
	//第二种方式定义
	var stu1 *Student = new(Student)
	stu1.Name = "stu1"
	stu1.Age = 30
	stu1.Score = 54
	head.next = stu1

	//实体3
	//第三种方式定义
	var stu2 *Student = &Student{}
	stu2.Name = "stu2"
	stu2.Age = 32
	stu2.Score = 100
	stu1.next = stu2

	fmt.Println(head)
	fmt.Println(*stu1)
	fmt.Println(*stu2)
}

//运行结果为:
{head 20 80 0xc000112480}
{stu1 30 54 0xc0001124b0}
{stu2 32 100 <nil>}

2、存储方式

示例:值类型存储方式地址空间连续。 

package main

import "fmt"

//结构体定义
type Student struct {
	Name  string
	Age   int
	Score float32
}

func main() {

	var head Student
	head.Name = "head"
	head.Age = 20
	head.Score = 80

	fmt.Printf("Name:%p\n", &head.Name)
	fmt.Printf("Age:%p\n", &head.Age)
	fmt.Printf("Score:%p\n", &head.Score)
}

//运行结果为:
Name:0xc00005c3c0
Age:0xc00005c3d0
Score:0xc00005c3d8

3、链表更新

链表大小不固定,地址不连续,长度不固定,链表中第一个元素称为头部,最后一个元素指针指向nil。 

链表分类:单链表、双链表、循环单链表、循环双链表。

示例:用遍历的方式遍历结构体。

定义好头部体和前三个结构体,第四个结构体采用for循环。

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 = 20
	head.Score = 80

	//第二个结构体
	var stu1 Student
	stu1.Name = "stu1"
	stu1.Age = 30
	stu1.Score = 90
	//头部结构体---->第一个结构体
	head.next = &stu1

	//第三个结构体
	var stu2 Student
	stu2.Name = "stu2"
	stu2.Age = 40
	stu2.Score = 100
	//第一个结构体---->第二个结构体
	stu1.next = &stu2

	//第四个结构体
	var stu3 Student
	stu3.Name = "stu3"
	stu3.Age = 50
	stu3.Score = 200
	//第二个结构体---->第三个结构体
	stu2.next = &stu3

	//尾部添加节点
	//申明变量
	insterTail(&stu3)

	//定义结构体指针,从头部索引
	//var tmp *Student = &head
	Req(&head)

}

//函数方式遍历结构体链表
func Req(tmp *Student) {
	//tmp指针指向下一个结构体地址,加*号就是下个结构体
	//遍历输出链表中每个结构体
	for tmp != nil {
		fmt.Println(*tmp)
		//tmp变更为下一个结构体地址
		tmp = tmp.next
	}
}

//添加结构体节点
func insterTail(tail *Student) {
	for i := 4; i < 10; i++ {
		//节点定义
		var stu Student = Student{
			Name:  fmt.Sprintf("stu%d", i),
			Age:   rand.Intn(100),
			Score: rand.Float32() * 200,
		}
		tail.next = &stu
		tail = &stu
	}

}

//运行结果为:
{head 20 80 0xc0000924b0}
{stu1 30 90 0xc0000924e0}
{stu2 40 100 0xc000092510}
{stu3 50 200 0xc000092540}
{stu4 81 188.10182 0xc000092570}
{stu5 47 87.54284 0xc0000925a0}
{stu6 81 137.36461 0xc0000925d0}
{stu7 25 31.30385 0xc000092600}
{stu8 56 60.182373 0xc000092630}
{stu9 94 162.72798 <nil>}

根据上面的代码进行优化处理:

只定义好头部体,其他结构体都用for循环来表示。

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 = 20
	head.Score = 80

	//尾部添加节点
	//申明变量
	insterTail(&head)

	//定义结构体指针,从头部索引
	Req(&head)

}

//遍历结构体链表
func Req(tmp *Student) {
	//tmp指针指向下一个结构体地址,加*号就是下个结构体
	//遍历输出链表中每个结构体
	for tmp != nil {
		fmt.Println(*tmp)
		//tmp变更为下一个结构体地址
		tmp = tmp.next
	}
}

//添加结构体节点
func insterTail(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() * 200,
		}
		tail.next = &stu
		tail = &stu
	}
}

//运行结果为:
{head 20 80 0xc0000c2480}
{stu0 81 188.10182 0xc0000c24b0}
{stu1 47 87.54284 0xc0000c24e0}
{stu2 81 137.36461 0xc0000c2510}
{stu3 25 31.30385 0xc0000c2540}
{stu4 56 60.182373 0xc0000c2570}
{stu5 94 162.72798 0xc0000c25a0}
{stu6 62 76.13144 0xc0000c25d0}
{stu7 28 93.77797 0xc0000c2600}
{stu8 11 58.62037 0xc0000c2630}
{stu9 37 43.71061 <nil>}

4、头部添加结构体

示例:定义好头部结构体,如果想在前面添加结构体怎么操作?

第一种方式:

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 = 20
	head.Score = 80

	//调用头部插入函数
	insterHead(&head)

	//定义结构体指针,从头部索引
	Req(head)

}

//遍历结构体链表
func Req(tmp *Student) {
	//tmp指针指向下一个结构体地址,加*号就是下个结构体
	//遍历输出链表中每个结构体
	for tmp != nil {
		fmt.Println(*tmp)
		//tmp变更为下一个结构体地址
		tmp = tmp.next
	}
}

//添加结构体节点
func insterHead(top **Student) {
	for i := 0; i < 10; i++ {
		//节点定义
		var stu Student = Student{
			Name:  fmt.Sprintf("stu%d", i),
			Age:   rand.Intn(100),
			Score: rand.Float32() * 200,
		}
		stu.next = *top
		*top = &stu
	}
}

//运行结果为:
{stu9 37 43.71061 0xc0000c2630}
{stu8 11 58.62037 0xc0000c2600}
{stu7 28 93.77797 0xc0000c25d0}
{stu6 62 76.13144 0xc0000c25a0}
{stu5 94 162.72798 0xc0000c2570}
{stu4 56 60.182373 0xc0000c2540}
{stu3 25 31.30385 0xc0000c2510}
{stu2 81 137.36461 0xc0000c24e0}
{stu1 47 87.54284 0xc0000c24b0}
{stu0 81 188.10182 0xc0000c2480}
{head 20 80 <nil>}

第二种方式:

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 = 20
	head.Score = 80

	//调用头部插入函数
	insterHead(&head)

	//定义结构体指针,传入一个新的结构体,进行遍历
	Req(insterHead(&head))

}

//遍历结构体链表
func Req(tmp *Student) {
	//tmp指针指向下一个结构体地址,加*号就是下个结构体
	//遍历输出链表中每个结构体
	for tmp != nil {
		fmt.Println(*tmp)
		//tmp变更为下一个结构体地址
		tmp = tmp.next
	}
}

//添加结构体节点
func insterHead(top *Student) *Student {
	for i := 0; i < 10; i++ {
		//节点定义
		var stu Student = Student{
			Name:  fmt.Sprintf("stu%d", i),
			Age:   rand.Intn(100),
			Score: rand.Float32() * 200,
		}
		stu.next = top
		top = &stu
	}
	return top
}

//运行结果为:
{stu9 85 60.304535 0xc0000c2810}
{stu8 37 11.82413 0xc0000c27e0}
{stu7 29 15.890725 0xc0000c27b0}
{stu6 87 121.45068 0xc0000c2780}
{stu5 41 5.6606164 0xc0000c2750}
{stu4 90 139.34384 0xc0000c2720}
{stu3 87 41.316532 0xc0000c26f0}
{stu2 47 59.416515 0xc0000c26c0}
{stu1 28 172.49829 0xc0000c2690}
{stu0 95 72.17428 0xc0000c2480}
{head 20 80 <nil>}

总结:值类型如果想外部数据和函数处理结果同步,两种方法:

①传参指针

②return 返回值

5、指定位置插入

示例:在链表的指定位置,插入一条定义的结构体。

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 = 20
	head.Score = 80

	//尾部添加节点
	//申明变量
	insterTail(&head)

	//定义要插入的新节点
	var newNode *Student = &Student{
		Name:  "newNode",
		Age:   18,
		Score: 120,
	}

	//调用指定位置插入新节点
	addNode(&head, newNode)

	//定义结构体指针,从头部索引
	//var tmp *Student = &head
	Req(&head)

}

//遍历结构体链表
func Req(tmp *Student) {
	//tmp指针指向下一个结构体地址,加*号就是下个结构体
	//遍历输出链表中每个结构体
	for tmp != nil {
		fmt.Println(*tmp)
		//tmp变更为下一个结构体地址
		tmp = tmp.next
	}
}

//添加结构体节点
func insterTail(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() * 200,
		}
		tail.next = &stu
		tail = &stu
	}
}

//指定节点插入新节点
func addNode(tmp *Student, newNode *Student) {
	for tmp != nil {
		if tmp.Name == "stu5" {
			//把当前节点断掉,嫁接下一个节点
			newNode.next = tmp.next
			tmp.next = newNode
		}
		//插入节点指向下个节点
		tmp = tmp.next
	}
}

//运行结果为:
{head 20 80 0xc0001124b0}
{stu0 81 188.10182 0xc0001124e0}
{stu1 47 87.54284 0xc000112510}
{stu2 81 137.36461 0xc000112540}
{stu3 25 31.30385 0xc000112570}
{stu4 56 60.182373 0xc0001125a0}
{stu5 94 162.72798 0xc000112690}
{newNode 111 123 0xc0001125d0}
{stu6 62 76.13144 0xc000112600}
{stu7 28 93.77797 0xc000112630}
{stu8 11 58.62037 0xc000112660}
{stu9 37 43.71061 <nil>}

6、删除节点

示例:在一个链表中删除指定的节点。

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 = 20
	head.Score = 80

	//尾部添加节点
	//申明变量
	insterTail(&head)

	//定义删除函数
	delNode(&head)

	//定义结构体指针,从头部索引
	//var tmp *Student = &head
	Req(&head)

}

//遍历结构体链表
func Req(tmp *Student) {
	//tmp指针指向下一个结构体地址,加*号就是下个结构体
	//遍历输出链表中每个结构体
	for tmp != nil {
		fmt.Println(*tmp)
		//tmp变更为下一个结构体地址
		tmp = tmp.next
	}
}

//添加结构体节点
func insterTail(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() * 200,
		}
		tail.next = &stu
		tail = &stu
	}
}

//删除节点
func delNode(tmp *Student) {
	var prev = tmp
	for tmp != nil {
		if tmp.Name == "stu2" {
			prev.next = tmp.next
			break
		}
		//平移
		//前节点赋值
		prev = tmp
		//后节点赋值
		tmp = tmp.next
	}
}

//运行结果为:
{head 20 80 0xc0001124b0}
{stu0 81 188.10182 0xc0001124e0}
{stu1 47 87.54284 0xc000112540}
{stu3 25 31.30385 0xc000112570}
{stu4 56 60.182373 0xc0001125a0}
{stu5 94 162.72798 0xc0001125d0}
{stu6 62 76.13144 0xc000112600}
{stu7 28 93.77797 0xc000112630}
{stu8 11 58.62037 0xc000112660}
{stu9 37 43.71061 <nil>}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值