结构体的定义与初始化方法前面文章里都说了,这里来实际操作下结构体的嵌套相关操作。
一、结构体嵌套(链表)
定义公共链表结构体
type Student1 struct {
Name string
Age int
Score float32
next *Student1
}
1.1、向后嵌套
链表尾部赋值(增加)函数 - 一个一个的手动增加链表
func tailLink1() {
// 定义链表1(首个链表)
var head Student1
head.Name = "Head"
head.Age = 18
head.Score = 99
// 定义链表2
var stu1 Student1
stu1.Name = "stu1"
stu1.Age = 19
stu1.Score = 110
head.next = &stu1 // 设置head的next字段实现链表
// 定义链表3
var stu2 Student1
stu2.Name = "stu2"
stu2.Age = 20
stu2.Score = 120
stu1.next = &stu2 // 设置stu1的next字段实现链表
// 定义链表4
var stu3 Student1
stu3.Name = "stu3"
stu3.Age = 21
stu3.Score = 130
//stu3.next = nil // next字段的默认值为:nil(这行也可以不写)
stu2.next = &stu3 // 设置stu2的next字段实现链表
// 使用for循环来便利链表
var p *Student1 = &head
for p != nil {
fmt.Println(p)
p = p.next
}
}
// 执行结果为:
&{Head 18 99 0xc000138390}
&{stu1 19 110 0xc0001383c0}
&{stu2 20 120 0xc0001383f0}
&{stu3 21 130 <nil>}
链表尾部赋值(增加)函数 - for循环增加链表
package main
import (
"fmt"
"math/rand"
)
func tailLink2(p *Student1) {
// 接收首个链表
var tailenv = p
// 生成节点
for i := 0; i < 10; i++ {
var stu = Student1{
Name: fmt.Sprintf("stu%d", i),
Age: rand.Intn(100),
Score: rand.Float32() * 100,
}
// 将生成的第一个节点的内存地址赋值给首节点的next参数
tailenv.next = &stu // 给第一个链表增加next字段的值,循环第二次的时候给第二个链表增加next字段的值,依次类推
tailenv = &stu // 将生成的第一个节点赋值给首节点变量,方便下次循环时给next参数赋值
}
// 便利链表的函数执行,将head的内存地址传给便利链表的函数,遍历链表的函数来实现便利
trans(p)
}
func main() {
// 初始化head链表
var head *Student1 = new(Student1)
head.Name = "Head"
head.Age = 18
head.Score = 99
tailLink2(head) // 调用函数,将head链表传到函数里
}
上面的示例里便利链表用到的trans函数,内容如下:
func trans(p *Student1) {
for p != nil {
fmt.Println(*p)
p = p.next
}
}
1.2、向前嵌套
在首链表前面增加链表这里直接使用的for循环生成链表并增加链表操作,代码示例如下
package main
import (
"fmt"
"math/rand"
)
func headLink(p **Student1) { // **:表示指针的指针,函数的参数默认接收的是参数的副本(如果想在函数里直接修改外面的参数head,需要接收参数的指针也就是指针的指针)
// 生成链表
for i := 0; i < 10; i++ {
stu := Student1{
Name: fmt.Sprintf("stu%d", i),
Age: rand.Intn(100),
Score: rand.Float32() * 100,
}
// 将head链表赋值给新生成链表的next参数
stu.next = *p // 第一次循环:增加链表(stu0)的next字段的值为head链表。第二次循环:本次循环增链表(stu1)的next字段值为刚增加的链表(stu0)。第三次循环:本次循环增加的链表(stu2)的next字段的值为刚增加的链表(stu1)
*p = &stu // 第一次循环:head指针指向了新增加的链表(stu0)的地址。第二次循环:(stu0)的指针指向了第二次循环增加的链表(stu1)的内存地址。第三次循环:(stu1)的指针指向了第三次循环增加的链表(stu2)的内存地址
}
// 便利链表的函数执行,将head的内存地址传给便利链表的函数,遍历链表的函数来实现便利
trans(*p)
}
func main() {
var head *Student1 = new(Student1)
head.Name = "Head"
head.Age = 18
head.Score = 99
// 链表头部赋值与便利
headLink(&head)
}
// 执行结果为:
{stu9 37 21.855305 0xc0000b6510}
{stu8 11 29.310184 0xc0000b64e0}
{stu7 28 46.888985 0xc0000b64b0}
{stu6 62 38.06572 0xc0000b6480}
{stu5 94 81.36399 0xc0000b6450}
{stu4 56 30.091187 0xc0000b6420}
{stu3 25 15.651925 0xc0000b63f0}
{stu2 81 68.682304 0xc0000b63c0}
{stu1 47 43.77142 0xc0000b6390}
{stu0 81 94.05091 0xc0000b6360}
{Head 18 99 <nil>}
二、删除和插入指定链表
2.1、删除指定链表
package main
import (
"fmt"
"math/rand"
)
func headLink(p **Student1) { // **:表示指针的指针,函数的参数默认接收的是参数的副本(如果想在函数里直接修改外面的参数head,需要接收参数的指针也就是指针的指针)
// 生成链表
for i := 0; i < 10; i++ {
stu := Student1{
Name: fmt.Sprintf("stu%d", i),
Age: rand.Intn(100),
Score: rand.Float32() * 100,
}
// 将head链表赋值给新生成链表的next参数
stu.next = *p // 第一次循环:增加链表(stu0)的next字段的值为head链表。第二次循环:本次循环增链表(stu1)的next字段值为刚增加的链表(stu0)。第三次循环:本次循环增加的链表(stu2)的next字段的值为刚增加的链表(stu1)
*p = &stu // 第一次循环:head指针指向了新增加的链表(stu0)的地址。第二次循环:(stu0)的指针指向了第二次循环增加的链表(stu1)的内存地址。第三次循环:(stu1)的指针指向了第三次循环增加的链表(stu2)的内存地址
}
// 便利链表的函数执行,将head的内存地址传给便利链表的函数,遍历链表的函数来实现便利
trans(*p)
}
// 删除链表节点的函数
func delNode(p *Student1) {
var prev *Student1 = p // 1.此时prev的值是Head节点的值
for p != nil { // 2、循环开始
if p.Name == "stu6" { // 5.找到被删除的节点
prev.next = p.next // 6.将stu6的next值赋值给stu5的next(stu5.next -->stu7,就删掉了stu6)
break // 退出循环
}
prev = p // 3.循环五次,此时prev的值是stu5
p = p.next // 4.p的next地址是stu6的地址
}
}
func main() {
// 定义第一个链表参数
var head *Student1 = new(Student1)
head.Name = "Head"
head.Age = 18
head.Score = 99
// 链表头部赋值与便利
headLink(&head)
// 删除某个节点
delNode(head)
// 便利链表函数
trans(head)
}
// 执行结果为:
{stu9 37 21.855305 0xc000064510}
{stu8 11 29.310184 0xc0000644e0}
{stu7 28 46.888985 0xc0000644b0}
{stu6 62 38.06572 0xc000064480}
{stu5 94 81.36399 0xc000064450}
{stu4 56 30.091187 0xc000064420}
{stu3 25 15.651925 0xc0000643f0}
{stu2 81 68.682304 0xc0000643c0}
{stu1 47 43.77142 0xc000064390}
{stu0 81 94.05091 0xc000064360}
{Head 18 99 <nil>}
{stu9 37 21.855305 0xc000064510}
{stu8 11 29.310184 0xc0000644e0}
{stu7 28 46.888985 0xc000064480}
{stu5 94 81.36399 0xc000064450} // 此处发现stu6这个链表被删掉了
{stu4 56 30.091187 0xc000064420}
{stu3 25 15.651925 0xc0000643f0}
{stu2 81 68.682304 0xc0000643c0}
{stu1 47 43.77142 0xc000064390}
{stu0 81 94.05091 0xc000064360}
{Head 18 99 <nil>}
2.2、插入链表
package main
import (
"fmt"
"math/rand"
)
// 链表尾部赋值(增加)函数 - for循环增加链表
func tailLink2(p *Student1) {
// 接收首个链表
var tailenv = p
// 生成节点
for i := 0; i < 10; i++ {
var stu = Student1{
Name: fmt.Sprintf("stu%d", i),
Age: rand.Intn(100),
Score: rand.Float32() * 100,
}
// 将生成的第一个节点的内存地址赋值给首节点的next参数
tailenv.next = &stu // 给第一个链表增加next字段的值,循环第二次的时候给第二个链表增加next字段的值,依次类推
tailenv = &stu // 将生成的第一个节点赋值给首节点变量,方便下次循环时给next参数赋值
}
// 便利链表的函数执行,将head的内存地址传给便利链表的函数,遍历链表的函数来实现便利
trans(p)
}
// 插入链表节点的函数(此代码删除头节点有问题)
func addNode(p *Student1, newnode *Student1) {
for p != nil {
if p.Name == "stu5" { // 找到要被插入的节点
newnode.next = p.next // 将stu5.next赋值给newnode.next
p.next = newnode // 将stu5.next指向newnode
break // 退出循环
}
p = p.next // p的next地址赋值给p
}
}
func main() {
// 定义第一个链表参数
var head *Student1 = new(Student1)
head.Name = "Head"
head.Age = 18
head.Score = 99
// 链表尾部循环赋值与便利函数
tailLink2(head)
// 插入节点
var newNode *Student1 = new(Student1)
newNode.Name = "stuNewAdd"
newNode.Age = 18
newNode.Score = 99
addNode(head, newNode)
// 便利链表函数
trans(head)
}
// 执行结果为:
{Head 18 99 0xc000138360}
{stu0 81 94.05091 0xc000138390}
{stu1 47 43.77142 0xc0001383c0}
{stu2 81 68.682304 0xc0001383f0}
{stu3 25 15.651925 0xc000138420}
{stu4 56 30.091187 0xc000138450}
{stu5 94 81.36399 0xc000138480}
{stu6 62 38.06572 0xc0001384b0}
{stu7 28 46.888985 0xc0001384e0}
{stu8 11 29.310184 0xc000138510}
{stu9 37 21.855305 <nil>}
{Head 18 99 0xc000138360}
{stu0 81 94.05091 0xc000138390}
{stu1 47 43.77142 0xc0001383c0}
{stu2 81 68.682304 0xc0001383f0}
{stu3 25 15.651925 0xc000138420}
{stu4 56 30.091187 0xc000138450}
{stu5 94 81.36399 0xc000138750}
{stuNewAdd 18 99 0xc000138480} // 这里是插入的链表
{stu6 62 38.06572 0xc0001384b0}
{stu7 28 46.888985 0xc0001384e0}
{stu8 11 29.310184 0xc000138510}
{stu9 37 21.855305 <nil>}
三、嵌套结构体的字段冲突处理
//Address 地址结构体
type Address struct {
Province string
City string
CreateTime string
}
//Email 邮箱结构体
type Email struct {
Account string
CreateTime string
}
//User 用户结构体
type User struct {
Name string
Gender string
Address // Address结构体里有CreateTime
Email // Email结构体里面也有CreateTime(此时就出现了字段冲突)
}
func main() {
var user3 User
user3.Name = "Dream"
user3.Gender = "男"
// user3.CreateTime = "2019" // 这里直接调用CreateTime字段会发生冲突,所以需要指定结构体的CreateTime字段来调用
user3.Address.CreateTime = "2000" //指定Address结构体中的CreateTime
user3.Email.CreateTime = "2000" //指定Email结构体中的CreateTime
}
四、结构体二叉树
顾名思义,二叉树的意思即在一个根节点下面有两个子节点,两个子节点的每个节点还有两个子节点,具体如下图:
二叉树结构体定义
type Student struct {
Name string
Age int
Score int
left *Student
right *Student
}
创建二叉树
func testTree() {
var root *Student = new(Student)
root.Name = "stu_Head"
root.Age = 18
root.Score = 100
// root.left = nil
// root.right = nil
var left1 *Student = new(Student)
left1.Name = "stu_left"
left1.Age = 1
left1.Score = 1
root.left = left1
var right1 *Student = new(Student)
right1.Name = "stu_right"
right1.Age = 2
right1.Score = 2
root.right = right1
var left2 *Student = new(Student)
left2.Name = "left1_min"
left2.Age = 1
left2.Score = 1
left1.left = left2
// 便利二叉树
trans(root)
}
// 执行结果为:
&{left1_min 1 1 <nil> <nil>}
&{stu_left 1 1 0xc0000b63c0 <nil>}
&{stu_Head 18 100 0xc0000b6360 0xc0000b6390}
&{stu_right 2 2 <nil> <nil>}
遍历二叉树函数
// 递归便利二叉树
func trans(root *Student) {
if (root == nil) { // 定义结束条件
return
}
trans(root.left)
fmt.Println(root)
trans(root.right)
}