目录
前言
结构体是自定义复杂的数据结构,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>}