文章目录
- [Go 数据结构入门:线性表、顺序表、链表](#Go 数据结构入门:线性表、顺序表、链表)
- 一、什么是线性表?(一句话记住)
- 二、先看懂:内存长什么样(外层容器)
- 三、顺序表:内存中「连续存放」
- 四、链表:内存中「不连续、散落存放」
- [五、最强对比:顺序表 vs 链表](#五、最强对比:顺序表 vs 链表)
-
-
- [🔥 一眼看懂内存区别](#🔥 一眼看懂内存区别)
-
- [六、零基础总结(3 句话背会)](#六、零基础总结(3 句话背会))
Go 数据结构入门:线性表、顺序表、链表
大家好~前面我们学习了 Go 基础、指针,今天正式进入数据结构 。
很多同学觉得数据结构抽象难懂,我这篇用 「外层内存容器 + 内层格子布局」 画图讲解,一眼看清顺序表连续、链表不连续,零基础一遍看懂!
全篇包含:
✅ 什么是线性表(超级通俗)
✅ 顺序表:内存连续存放 (结构图)
✅ 链表:内存不连续、散落存放 (结构图)
✅ 顺序表 vs 链表 最强对比
✅ Go 代码演示
✅ 面试必问总结
一、什么是线性表?(一句话记住)
线性表 = 排成一条直线的元素序列。
就像:排队、一串珠子、一列火车...
特点:
-
有先后顺序
-
有第一个、最后一个
-
中间每个元素:前面叫前驱 ,后面叫后继
线性表只是逻辑结构 ,真正在内存里有两种实现:
1️⃣ 顺序表 (连续放)
2️⃣ 链表(分开放,指针连)
二、先看懂:内存长什么样(外层容器)
我们把 整个内存 画成一个 大矩形容器 ,里面是一个个带地址的小格子:
每个格子 = 1 字节,有唯一地址。
Plain
┌─────────────────────────────────────────────┐
│ 系统内存 │ ← 外层大容器
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │0x01 │ │0x02 │ │0x03 │ │0x04 │ │0x05 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │0x06 │ │0x07 │ │0x08 │ │0x09 │ │0x10 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
└─────────────────────────────────────────────┘
所有数据结构,本质就是:
怎么在这些格子里摆放数据。
三、顺序表:内存中「连续存放」
顺序表 = 一整块连续内存,元素紧紧挨在一起。
🔥 内存布局图(外层容器 + 内层连续)
Plain
┌─────────────────────────────────────────────┐
│ 内存 │
│ │
│ ┌─────┬─────┬─────┬─────┬─────┐ │
│ │ 10 │ 20 │ 30 │ 40 │ 50 │ │
│ └─────┴─────┴─────┴─────┴─────┘ │
│ ↑ 完全连续、紧凑挨着 │
│ │
└─────────────────────────────────────────────┘
特点
-
元素物理地址连续
-
支持随机访问(下标直接取,O (1))
优点
✅ 查找快
✅ 内存紧凑,无额外开销
缺点
❌ 插入 / 删除慢:后面元素要整体移动
❌ 需要一大块连续内存,内存不足易分配失败
Go 中的顺序表 = 切片 slice
go
package main
import "fmt"
func main() {
// 切片本质就是顺序表(连续内存)
arr := []int{10, 20, 30, 40, 50}
// 随机访问 O(1)
fmt.Println(arr[2]) // 30
}
四、链表:内存中「不连续、散落存放」
链表 = 元素可以散落在内存任意位置,只用指针串起来 。
就像小朋友手拉手,不用站在一起。
🔥 内存布局图(外层容器 + 内层散落)
Plain
┌─────────────────────────────────────────────┐
│ 内存 │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 10 │ │ 20 │ │ 30 │ │
│ │ Next├──────────→│ Next├────→│ Next├─→nil│
│ └──────┘ └──────┘ └──────┘ │
│ ↑ 不连续 ↑ 不连续 │
└─────────────────────────────────────────────┘
每个节点结构
Plain
┌─────────────────────┐
│ 数据域 │ ← 存值
│ 指针域 │ ← 存下一个节点地址
└─────────────────────┘
特点
-
物理空间不连续
-
逻辑连续(靠 Next 指针串联)
优点
✅ 插入 / 删除极快:只改指针
✅ 不需要连续内存,碎片利用率高
✅ 可随时无限扩容
缺点
❌ 查找慢:必须从头遍历
❌ 每个节点多存一个指针,额外开销
Go 实现简单链表
go
package main
import "fmt"
// 定义链表节点
type Node struct {
Val int
Next *Node
}
func main() {
// 构建 10 → 20 → 30
n1 := &Node{Val: 10}
n2 := &Node{Val: 20}
n3 := &Node{Val: 30}
n1.Next = n2
n2.Next = n3
// 遍历链表
cur := n1
for cur != nil {
fmt.Println(cur.Val)
cur = cur.Next
}
}
五、最强对比:顺序表 vs 链表
🔥 一眼看懂内存区别
Plain
【顺序表:连续】
┌─────────────────────────────────┐
│ 内存 │
│ ┌─────┬─────┬─────┬─────┐ │
│ │ 10 │ 20 │ 30 │ 40 │ │
│ └─────┴─────┴─────┴─────┘ │
└─────────────────────────────────┘
【链表:不连续】
┌─────────────────────────────────────────────┐
│ 内存 │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ 10 │ │ 20 │ │ 30 │ │
│ └──┬──┘ └──┬──┘ └──┬──┘ │
│ └──────────────└──────────────┘ │
│ 指针连接,物理位置完全不连续 │
└─────────────────────────────────────────────┘
| 维度 | 顺序表 | 链表 |
|---|---|---|
| 内存布局 | 连续 | 不连续、散落 |
| 查找 | 快 O (1) | 慢 O (n) |
| 插入 / 删除 | 慢(需要移动数据) | 快(只改指针) |
| 内存占用 | 小(无额外开销) | 大(每个节点存指针) |
| 扩容 | 需重新分配连续内存 | 随时加节点 |
| 适用场景 | 查询多、增删少 | 增删多、频繁插入 |
六、零基础总结(3 句话背会)
-
线性表 = 排成一条直线的元素
-
顺序表 = 内存连续存放,查找快、增删慢
-
链表 = 指针连接,增删快、查找慢
👍点赞 + ⭐收藏 + 📌关注,更新第一时间不迷路!
(注:文档部分内容可能由 AI 生成)