【数据结构入门】
👉 看 ArrayList
源码,说“基于数组”,但数组到底怎么“动态扩容”?
👉 LinkedList
是“链表”,可链表长什么样?为啥插入快?
👉 HashMap
说“数组 + 链表/红黑树”,红黑树又是啥?看着就头大……
集合框架的底层,其实就是各种数据结构的组合应用。
一、什么是数据结构?
简单说:数据结构就是数据的组织方式。
就像你整理衣柜:
- 把衣服叠好堆起来 → 像 数组
- 用衣架一个接一个挂起来 → 像 链表
- 按季节分类放进不同抽屉 → 像 哈希表
✅ 好的数据结构,能让“存、取、查、改”更快更省空间!
二、1. 数组(Array)—— 连续的“格子”
🎯 核心特点
- 内存连续:所有元素在内存中挨着存放
- 固定长度:创建时必须指定大小,不能变
- 随机访问快:通过索引
index
直接定位,O(1)
时间
int[] arr = new int[5]; // 创建长度为 5 的数组
arr[0] = 10; // 直接通过索引赋值
int value = arr[2]; // 直接通过索引取值
🖼️ 图示
内存地址: 1000 1004 1008 1012 1016+----+----+----+----+----+
数组 arr: | 10 | ? | 30 | ? | ? |+----+----+----+----+----+
索引: 0 1 2 3 4
✅ 优点:查询快(
get(index)
O(1)
)
❌ 缺点:长度固定,插入/删除慢(要移动后面所有元素)
🔧 在集合中的应用
ArrayList
:基于数组实现,通过“扩容”解决长度固定问题HashMap
的“桶数组”:存储链表或红黑树的根节点
三、2. 链表(Linked List)—— 用“绳子”串起来的珠子
🎯 核心特点
- 内存不连续:每个节点(Node)分散在内存各处
- 动态大小:可以随时添加或删除节点
- 增删快:只要修改“指针”(引用),
O(1)
时间(已知节点位置) - 查询慢:必须从头开始一个一个找,
O(n)
时间
🖼️ 图示:单向链表
+----+----+ +----+----+ +----+----+
head ->| 10 | --o--->| 20 | --o--->| 30 |null|+----+----+ +----+----+ +----+----+数据 指针 数据 指针 数据 指针
每个节点包含两部分:
- 数据域:存实际数据(如 10)
- 指针域:存下一个节点的地址(引用)
🖼️ 图示:双向链表(LinkedList
用它)
+------+----+------+ +------+----+------+ +------+----+------+
head ->| prev | 10 | next |<--->| prev | 20 | next |<--->| prev | 30 | next || null | | o---+ +------+----+---o | +---o----+----+ null |+------+----+------+ | || | |+----------------------------------+ ||+--------------------------------------------+
多了一个
prev
指针,指向前一个节点,可以双向遍历。
🔧 在集合中的应用
LinkedList
:基于双向链表实现,头尾增删极快HashMap
的“桶”:当多个元素哈希到同一个位置时,用链表串起来
四、3. 栈(Stack)—— 叠盘子
🎯 核心特点
- 后进先出(LIFO):最后放的盘子,最先拿走
- 只允许在一端操作:入栈(push) 和 出栈(pop)
🖼️ 图示
|------| <- 出栈 (pop)| C ||------|| B ||------|| A ||------| <- 入栈 (push)| 底 |
🔧 在集合中的应用
ArrayDeque
:可以用作栈(push()
/pop()
)- 算法:递归、括号匹配、表达式求值
五、4. 队列(Queue)—— 排队买票
🎯 核心特点
- 先进先出(FIFO):先排队的人,先买到票
- 一端入队(
offer
),另一端出队(poll
)
🖼️ 图示
入队 (offer) -> | A | B | C | D | -> 出队 (poll)头 尾
🖼️ 双端队列(Deque)—— 两头都能进出
左进 -> | A | B | C | D | <- 右进| D | C | B | A | <- 左出
右出 -> | A | B | C | D | <- 左进
🔧 在集合中的应用
ArrayDeque
:基于循环数组实现双端队列,性能高PriorityQueue
:基于堆实现的优先级队列,按优先级出队
六、5. 哈希表(Hash Table)—— 用“钥匙”找抽屉
🎯 核心思想
- 给每个“数据”算一个“指纹”(哈希值)
- 用“指纹”决定它该放在哪个“抽屉”(桶 bucket)
🖼️ 图示:哈希表基本结构
桶数组 (buckets)
+-----------------+
| bucket 0 | -> | A:10 | -> | E:50 | (链表法解决冲突)
+-----------------+
| bucket 1 | -> | B:20 |
+-----------------+
| bucket 2 | -> null
+-----------------+
| bucket 3 | -> | C:30 | -> | F:60 | -> | G:70 |
+-----------------+
| bucket 4 | -> | D:40 |
+-----------------+
🔍 步骤:
- 计算哈希:
hash("A") = 0
- 定位桶:放入
bucket 0
- 解决冲突:如果
hash("E")
也等于 0,就用链表串起来(拉链法)
🔧 在集合中的应用
HashMap
/HashSet
:核心就是哈希表LinkedHashMap
:哈希表 + 双向链表(维护顺序)
七、6. 树(Tree)—— 层层分级的组织结构
🎯 核心概念
- 根节点(Root):最顶层,只有一个
- 父节点、子节点:上下级关系
- 叶子节点(Leaf):没有子节点
- 深度(Depth):从根到节点的边数
🖼️ 图示:普通树
A <- 根节点/ | \B C D <- 内部节点/ \ |E F G <- 叶子节点
🖼️ 二叉树(Binary Tree)—— 每个节点最多两个孩子
5/ \3 8/ \ \2 4 9
八、7. 二叉搜索树(BST)—— 自动排序的二叉树
🎯 核心规则
- 左子树所有节点 < 根节点
- 右子树所有节点 > 根节点
- 左右子树也都是 BST
🖼️ 图示
5/ \3 8/ \ \2 4 9/1
✅ 优点:查找、插入、删除平均
O(log n)
❌ 缺点:可能退化成链表(如插入 1,2,3,4,5)
九、8. 平衡二叉树(AVL Tree)—— 自动“瘦身”的 BST
🎯 核心思想
- 在 BST 基础上,左右子树高度差不超过 1
- 插入/删除后,通过“旋转”保持平衡
✅ 优点:严格平衡,查找稳定
O(log n)
❌ 缺点:旋转操作稍复杂,插入删除可能稍慢
十、9. 红黑树(Red-Black Tree)—— “近似平衡”的 BST
🎯 核心规则(5条)
- 节点是红色或黑色
- 根节点是黑色
- 所有叶子(null)是黑色
- 红色节点的子节点必须是黑色(不能有两个连续红节点)
- 从任一节点到其每个叶子的所有路径包含相同数目的黑色节点
🖼️ 图示(简化)
B(5)/ \R(3) B(8)/ \ \B(2) B(4) R(9)/B(1)
✅ 优点:
- 近似平衡,查找、插入、删除
O(log n)
- 旋转比 AVL 少,综合性能更好
🔧 在集合中的应用
TreeMap
/TreeSet
:基于红黑树实现,自动排序HashMap
(JDK 8+):当链表长度 > 8 且数组长度 ≥ 64 时,链表转红黑树,防止查找退化到O(n)
十一、总结:一张表搞懂数据结构与集合的对应关系
数据结构 | 特点 | 在 Java 集合中的应用 |
---|---|---|
数组 | 连续内存,查询快,增删慢 | ArrayList , HashMap 的桶数组 |
链表 | 内存分散,增删快,查询慢 | LinkedList , HashMap 的冲突链表 |
栈 | LIFO(后进先出) | ArrayDeque (可用作栈) |
队列 | FIFO(先进先出) | ArrayDeque , PriorityQueue |
哈希表 | 通过哈希快速定位 | HashMap , HashSet , LinkedHashMap |
红黑树 | 近似平衡,有序,O(log n) | TreeMap , TreeSet , HashMap (链表转树) |
🔚 最后一句话
数据结构是“内功”,集合框架是“招式”。
只有理解了数组、链表、哈希表、红黑树这些“内功心法”,
你才能真正看懂ArrayList
、HashMap
、TreeSet
这些“绝世武功”的精妙之处。
掌握它,你才能从“调用 API”升级到“理解设计、优化性能、写出大师级代码”!
希望这篇图文并茂的数据结构入门,能帮你扫清集合框架学习路上的障碍!