目录
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
使用链表结构可以避免在使用数组时需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
链表允许插入和移除表上任意位置上的结点,但是不允许随机存取。链表有三种类型:单向链表、双向链表以及循环链表。
结构体是自定义复杂数据结构,struct里面可以包含多个字段(属性),struct类型到可以定义方法,和函数有区分,struct属于值类型,且可以做嵌套,Go中没有Class类型,只有struct类型。
struct定义的三种形式:其中2和3都是返回结构体的指针。
1: var stu Student
2: var stu *Student = new (Student)
3: var stu *Student = &Student {}
存储方式
值类型存储方式地址空间连续
示例
package main
import "fmt"
type Student struct {
Name string
Age int32
Score float32
}
func main() {
var stu *Student = &Student{
Name: "zhangsan",
Age: 18,
Score: 90,
}
fmt.Printf("Name :%p\n", &stu.Name)
fmt.Printf("Age :%p\n", &stu.Age)
fmt.Printf("Score:%p\n", &stu.Score)
}
运行结果
Name :0xc000004078
Age :0xc000004088
Score:0xc00000408c
利用 Struct 可以包容多种数据类型的特性,使用它作为链表的结点是最合适不过了。一个结构体内可以包含若干成员,这些成员可以是基本类型、自定义类型、数组类型,也可以是指针类型。这里可以使用指针类型成员来存放下一个结点的地址。
使用 Struct 定义一个单向链表。
type Node struct {
Data int
Next *node
}
链表更新
package main
import "fmt"
type Student struct {
Name string
age int
city string
next *Student
}
func main() {
//头部结构体
var head Student
head.Name = "zhangsan"
head.age = 20
head.city = "nj"
//第二个结构体
var stu1 Student
stu1.Name = "lisi"
stu1.age = 22
stu1.city = "wh"
//头部指向第二个结构体地址
head.next = &stu1
//第三个结构体
var stu2 Student
stu2.Name = "wangwu"
stu2.age = 26
stu2.city = "wh"
//第二个指向第三个结构体地址
stu1.next = &stu2
Rey(&head)
//定义结构体指针 从头部索引
//var a *Student = &head
}
func Rey(a *Student) {
//遍历输出链表中每一个结构体
for a != nil {
fmt.Println(*a)
a = a.next
}
}
结果
{zhangsan 20 nj 0xc0000784b0}
{lisi 22 wh 0xc0000784e0}
{wangwu 26 wh <nil>}
链表实现增删改查
头部添加链表
package main
import (
"fmt"
)
//链表的增删改查
//首先定义结构体
type Head struct {
User string
pwd string
next *Head //链表
}
//头部添加
func AddHead(h **Head) {
for i := 0; i < 10; i++ {
var AddHead Head = Head{
User: fmt.Sprintf("node%d", i+1),
pwd: fmt.Sprintf("love%d", i),
}
AddHead.next = *h
*h = &AddHead
}
}
//遍历链表
func Rey(list *Head) {
for list != nil {
fmt.Println(*list)
//让list变为下一结构体地址
list = list.next
}
}
func main() {
//头部链表
var head *Head = &Head{
User: "张三",
pwd: "love789",
}
//调用头部添加的链表
AddHead(&head)
//从头部索引
Rey(head)
}
运行结果
{node10 love9 0xc0000c2600}
{node9 love8 0xc0000c25d0}
{node8 love7 0xc0000c25a0}
{node7 love6 0xc0000c2570}
{node6 love5 0xc0000c2540}
{node5 love4 0xc0000c2510}
{node4 love3 0xc0000c24e0}
{node3 love2 0xc0000c24b0}
{node2 love1 0xc0000c2480}
{node1 love0 0xc0000c2450}
{张三 love789 <nil>}
尾添加链表
package main
import (
"fmt"
)
//链表的增删改查
//首先定义结构体
type Head struct {
User string
pwd string
next *Head //链表
}
//尾部添加
func AddTail(a *Head) {
for i := 0; i < 10; i++ {
var AddTail Head = Head{
User: fmt.Sprintf("node%d", i+1),
pwd: fmt.Sprintf("love%d", i),
}
a.next = &AddTail
a = &AddTail
}
}
//遍历链表
func Rey(list *Head) {
for list != nil {
fmt.Println(*list)
//让list变为下一结构体地址
list = list.next
}
}
func main() {
//头部链表
var head *Head = &Head{
User: "张三",
pwd: "love789",
}
//从尾部添加的链表
AddTail(head)
//从头部索引
Rey(head)
}
从中间任意添加链表
package main
import (
"fmt"
)
//链表的增删改查
//首先定义结构体
type Head struct {
User string
pwd string
next *Head //链表
}
//头部添加
func AddHead(h **Head) {
for i := 0; i < 10; i++ {
var AddHead Head = Head{
User: fmt.Sprintf("node%d", i+1),
pwd: fmt.Sprintf("love%d", i),
}
AddHead.next = *h
*h = &AddHead
}
}
//任意位置添加链表
func AddRandom(a *Head, n *Head) {
for a != nil {
if a.User == "node2" {
//切换next
n.next = a.next
a.next = n
}
a = a.next
}
}
//遍历链表
func Rey(list *Head) {
for list != nil {
fmt.Println(*list)
//让list变为下一结构体地址
list = list.next
}
}
func main() {
//头部链表
var head *Head = &Head{
User: "张三",
pwd: "love789",
}
定义一个中间连接的链表块
var NewHead = &Head{
User: "王五",
pwd: "123456",
}
//调用头部添加的链表
AddHead(&head)
//调用任意位置添加的链表
AddRandom(head, NewHead)
//从头部索引
Rey(head)
}
运行结果
{node10 love9 0xc000078660}
{node9 love8 0xc000078630}
{node8 love7 0xc000078600}
{node7 love6 0xc0000785d0}
{node6 love5 0xc0000785a0}
{node5 love4 0xc000078570}
{node4 love3 0xc000078540}
{node3 love2 0xc000078510}
{node2 love1 0xc0000784b0}
{王五 123456 0xc0000784e0}
{node1 love0 0xc000078480}
{张三 love789 <nil>}
修改链表(1-2)
package main
import (
"fmt"
)
//链表的增删改查
//首先定义结构体
type Head struct {
User string
pwd string
next *Head //链表
}
//头部添加
func AddHead(h **Head) {
for i := 0; i < 10; i++ {
var AddHead Head = Head{
User: fmt.Sprintf("node%d", i+1),
pwd: fmt.Sprintf("love%d", i),
}
AddHead.next = *h
*h = &AddHead
}
}
//任意位置添加链表
func AddRandom(a *Head, n *Head) {
for a != nil {
if a.User == "node2" {
//切换next
n.next = a.next
a.next = n
}
a = a.next
}
}
func UpdataHead(u *Head, name string, n *Head) {
var up = u
for u != nil {
if u.User == name {
up.next = u.next
break
}
// up = u
// u = u.next
if u.User == name {
n.next = u.next
u.next = n
}
up = u
u = u.next
}
}
//遍历链表
func Rey(list *Head) {
for list != nil {
fmt.Println(*list)
//让list变为下一结构体地址
list = list.next
}
}
func main() {
//头部链表
var head *Head = &Head{
User: "张三",
pwd: "love789",
}
//定义一个中间连接的链表块
var NewHead = &Head{
User: "王五",
pwd: "123456",
}
//调用头部添加的链表
AddHead(&head)
//调用任意位置添加的链表
AddRandom(head, NewHead)
//修改
UpdataHead(head, "node3", NewHead)
//从头部索引
Rey(head)
}
2、
package main
import (
"fmt"
)
//链表的增删改查
//首先定义结构体
type Head struct {
User string
pwd string
next *Head //链表
}
//头部添加
func AddHead(h **Head) {
for i := 0; i < 10; i++ {
var AddHead Head = Head{
User: fmt.Sprintf("node%d", i+1),
pwd: fmt.Sprintf("love%d", i),
}
AddHead.next = *h
*h = &AddHead
}
}
//任意位置添加链表
func AddRandom(a *Head, n *Head) {
for a != nil {
if a.User == "node2" {
//切换next
n.next = a.next
a.next = n
}
a = a.next
}
}
//修改链表
func modifyStudentNode(head *Head, name string, n *Head) {
temp := head
//思路:
//1.找到要修改的结点的no,和temp.next.no作比较
for temp != nil {
if temp.next.User == name {
//说明我们已经找到这个要修改的结点了
head.next = temp.next
temp.next = n
break
}
temp = temp.next
head = temp
}
}
//遍历链表
func Rey(list *Head) {
for list != nil {
fmt.Println(*list)
//让list变为下一结构体地址
list = list.next
}
}
func main() {
//头部链表
var head *Head = &Head{
User: "张三",
pwd: "love789",
}
//定义一个中间连接的链表块
var NewHead = &Head{
User: "王五",
pwd: "123456",
}
//调用头部添加的链表
AddHead(&head)
//调用任意位置添加的链表
AddRandom(head, NewHead)
modifyStudentNode(head, "node2", NewHead)
//从头部索引
Rey(head)
}
修改结果
{node10 love9 0xc0000c2630}
{node9 love8 0xc0000c2600}
{node8 love7 0xc0000c25d0}
{node7 love6 0xc0000c25a0}
{node6 love5 0xc0000c2570}
{node5 love4 0xc0000c2540}
{node4 love3 0xc0000c2510}
{node3 love2 0xc0000c2480}
{王五 123456 0xc0000c24b0}
{node1 love0 0xc0000c2450}
{张三 love789 <nil>}
删除链表
package main
import (
"fmt"
)
//链表的增删改查
//首先定义结构体
type Head struct {
User string
pwd string
next *Head //链表
}
//头部添加
func AddHead(h **Head) {
for i := 0; i < 10; i++ {
var AddHead Head = Head{
User: fmt.Sprintf("node%d", i+1),
pwd: fmt.Sprintf("love%d", i),
}
AddHead.next = *h
*h = &AddHead
}
}
//删除链表
func deleteHead(d *Head) {
var del = d
for d != nil {
if d.User == "node5" {
del.next = d.next
break
}
del = d
d = d.next
}
}
//遍历链表
func Rey(list *Head) {
for list != nil {
fmt.Println(*list)
//让list变为下一结构体地址
list = list.next
}
}
func main() {
//头部链表
var head *Head = &Head{
User: "张三",
pwd: "love789",
}
//调用头部添加的链表
AddHead(&head)
//调用删除
deleteHead(head)
//从头部索引
Rey(head)
}
运行结果
{node10 love9 0xc000078630}
{node9 love8 0xc000078600}
{node8 love7 0xc0000785d0}
{node7 love6 0xc0000785a0}
{node6 love5 0xc000078540}
{node4 love3 0xc000078510}
{node3 love2 0xc0000784e0}
{node2 love1 0xc0000784b0}
{node1 love0 0xc000078480}
{张三 love789 <nil>}
二叉树
满足以下两个条件的树就是二叉树:
1.本身是有序树;
2.树中包含的各个节点的度不能超过2,即只能是0、1或者2;
示意图:
前序遍历
前序遍历二叉树——根左右
package main
import "fmt"
//定义结构体
type Student struct {
Name string
Age int
Score float32
left *Student
right*Student
}
/*二叉树*/
func main(){
//根节点
var root student
root.Name = "root"
root.Age = 10
root. Score = 90
//左子树
var left1 student
left1.Name = "left1"
left1.Age = 20
left1.Score = 80
root.left = &left1
//右子树
var right1 student
right1. Name = "right1”
right1. Age = 30
right1. Score - 70
root.right - &right1
//二级左子树
var left2 Student
left2.Name = "left2”
left2.Age = 40
left2.Score = 60
left1.left = &left2
//调用遍历函数
Req(&root)
}
//递归算法遍历整颗二叉树
func Req(rootl *student){
if root == nil {
return
}
fmt.Println(root)
//遍历左子树
Req(root.left)
//遍历右子树
Req(root.right)
}
运行结果
&{root 10 90 exce880764be exce880764ee}
&{left1 28 80 exce88876510<nil>}
&{left2 40 60 <nil><nil>}
&{right1 30 70 <nil> <nil>}
中序遍历——左根右
func Req(rootl *student){
if root == nil {
return
}
//遍历左子树
Req(root.left)
fmt.Println(root)
//遍历右子树
Req(root.right)
}
后序遍历——左右根
func Req(rootl *student){
if root == nil {
return
}
//遍历左子树
Req(root.left)
//遍历右子树
Req(root.right)
fmt.Println(root)
}