结构体的定义与初始化方法前面文章里都说了,这里来实际操作下结构体的嵌套相关操作。

 

一、结构体嵌套(链表)

定义公共链表结构体

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
}

  

 

 

四、结构体二叉树

顾名思义,二叉树的意思即在一个根节点下面有两个子节点,两个子节点的每个节点还有两个子节点,具体如下图:

go语言中结构体嵌套 golang 内嵌数组结构体赋值_赋值

 

 二叉树结构体定义

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)
}