Java 常用数据结构:API + 实现类型 + 核心原理 + 例子 + 选型与性能(完整版)
目标:把“怎么用(API)”和“为什么快/慢(实现原理)”放在同一份文档里。 约定:
- 复杂度以 JDK 常见实现为准(均摊/平均),极端情况会更差。
- 示例默认 import java.util.*;(并发类额外写全名)。
- 推荐:左边接口,右边实现(例如 Deque<Integer> dq = new ArrayDeque<>();)。
0) Java 集合框架总览(正确关系)
- Collection:List / Set / Queue
- Deque:Queue 的子接口(双端队列,可当栈)
- Map:独立体系,不属于 Collection

1) 数组 Array(T[] / int[])
实现类型与原理
- JVM 原生连续内存(逻辑上连续),通过下标偏移寻址
- 随机访问直接 O(1),插删需要整体搬移
常用 API/语法
- a.length
- a[i] 读写
- Arrays.sort(a)
- Arrays.binarySearch(a, key)
- Arrays.copyOf(a, n)
- System.arraycopy(…)
示例
int[] a = {3, 1, 2};
Arrays.sort(a); // [1,2,3]
int idx = Arrays.binarySearch(a, 2); // 1
什么时候用
- 原地算法、性能敏感、长度固定或可预估(计数、双指针、前缀和)
性能
- 访问 O(1)
- 中间插删 O(n)
- 内存开销最低
2) List(有序、可重复、可按下标)
2.1 ArrayList(动态数组,最常用)
实现类型与原理
- 底层:Object[] elementData
- 扩容:容量不足时创建新数组 + System.arraycopy 拷贝
- JDK 常用扩容策略:按比例增长(大致 1.5 倍,细节与版本有关)
- 随机访问快;中间插删慢(搬移)
常用 API
- add(e), add(i,e)
- get(i), set(i,e)
- remove(i), remove(obj)
- size(), isEmpty(), clear()
- contains, indexOf
- subList(l,r)(视图,修改会影响原 list)
示例
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(1, 15); // [10,15,20]
int x = list.get(2); // 20
list.remove(Integer.valueOf(15));
什么时候用
- 频繁 get/set、遍历、尾部追加
- LeetCode 默认 list 选它
性能
- get/set:O(1)
- 尾插:均摊 O(1)
- 中间插删:O(n)
- 额外:扩容会有一次性 O(n) 拷贝
2.2 LinkedList(双向链表,实现 List + Deque)
实现类型与原理
- 底层:双向链表节点 Node{E item; Node next; Node prev}
- 头尾操作 O(1)
- 随机访问 O(n)(要从头/尾走链)
- 内存开销大(节点对象 + prev/next)
常用 API(Deque 语义更常用)
- addFirst/addLast, offerFirst/offerLast
- pollFirst/pollLast, removeFirst/removeLast
- peekFirst/peekLast
示例
LinkedList<Integer> ll = new LinkedList<>();
ll.addLast(1);
ll.addLast(2);
ll.addFirst(0); // 0 1 2
int a = ll.pollFirst(); // 0
什么时候用
- 需要频繁头尾增删且数据量不大
- 但栈/队列更推荐 ArrayDeque
性能
- 头尾增删:O(1)
- get(i):O(n)
- 内存:比 ArrayList/ArrayDeque 更重
2.3 Vector / Stack(历史遗留,不推荐)
- Vector:动态数组 + 方法同步(锁开销)
- Stack:继承 Vector,作为栈不如 ArrayDeque
3) Deque / Queue(栈、队列、双端队列)
3.1 ArrayDeque(栈/队列首选)
实现类型与原理
- 底层:循环数组(环形缓冲区)Object[] elements
- 维护 head/tail 下标,通过位运算/取模实现环形
- 头尾增删无需搬移,O(1)
- 扩容:数组满时重建更大数组并按顺序搬移一次
- 不允许 null(用 null 作为空槽标记)
常用 API
- 队列(FIFO):offer, poll, peek
- 栈(LIFO):push, pop, peek
- 双端:offerFirst/offerLast, pollFirst/pollLast, peekFirst/peekLast
示例(队列 + 栈)
Deque<Integer> dq = new ArrayDeque<>();
// 队列
dq.offer(1);
dq.offer(2);
int q = dq.poll(); // 1
// 栈
dq.push(10);
dq.push(20);
int s = dq.pop(); // 20
什么时候用
- BFS 队列、滑窗单调队列、单调栈、括号匹配、DFS 模拟栈
- 几乎所有“栈/队列”刷题场景首选
性能
- 头尾操作:O(1)
- 通常快于 LinkedList,内存更省
- 注意:pop() 空时抛异常,安全写法用 pollFirst() 判断
3.2 PriorityQueue(堆,优先队列)
实现类型与原理
- 底层:数组实现的二叉堆(完全二叉树)
- 默认:小根堆(最小值在堆顶)
- offer:上浮(sift up)
- poll:取顶后把末尾放顶再下沉(sift down)
- 支持比较器自定义顺序
常用 API
- offer/add, poll/remove, peek
- size, isEmpty
示例(小根堆/大根堆)
PriorityQueue<Integer> minH = new PriorityQueue<>();
minH.offer(3); minH.offer(1);
int a = minH.poll(); // 1
PriorityQueue<Integer> maxH = new PriorityQueue<>(Collections.reverseOrder());
maxH.offer(3); maxH.offer(1);
int b = maxH.poll(); // 3
什么时候用
- TopK、实时最值、合并 K 路、Dijkstra/Prim、贪心调度
性能
- 入/出堆:O(log n)
- peek:O(1)
- contains/删除任意元素:O(n)(不适合作 Set)
3.3 Queue 的并发实现(工程)
- ConcurrentLinkedQueue:无锁非阻塞 FIFO(高并发)
- LinkedBlockingQueue / ArrayBlockingQueue:阻塞队列(线程协作)
- 原理涉及 CAS/锁/条件变量,通常不用于刷题
4) Set(去重集合)
4.1 HashSet(基于 HashMap)
实现类型与原理
-
内部用 HashMap<E, Object> 存储元素作为 key
-
value 是固定哨兵对象(只占位)
-
哈希表:数组 + 链表/红黑树(JDK8+)
- 低碰撞:链表
- 高碰撞:链表可能树化为红黑树(降低极端退化)
-
依赖 hashCode() 与 equals()
常用 API
- add, remove, contains
- size, isEmpty, clear
- 遍历:for-each / iterator
示例
Set<String> s = new HashSet<>();
s.add("a"); s.add("b");
boolean ok = s.contains("b");
s.remove("a");
什么时候用
- 判重、集合运算、滑窗去重、两数之和判存在
性能
- 平均 add/contains/remove:O(1)
- 极端:碰撞很严重会变差(JDK8+ 有树化缓解)
4.2 LinkedHashSet(HashSet + 双向链表保持插入顺序)
实现类型与原理
- 基于 LinkedHashMap
- 在哈希表基础上维护双向链表,记录插入顺序
- 遍历顺序稳定
示例
Set<Integer> s = new LinkedHashSet<>();
s.add(3); s.add(1); s.add(2);
// 遍历:3,1,2
什么时候用
- 去重 + 需要保持插入顺序输出
性能
- 平均 O(1),略高于 HashSet(链表维护)
4.3 TreeSet(红黑树,有序集合)
实现类型与原理
- 基于 TreeMap(元素作为 key)
- 红黑树:平衡二叉搜索树,保证高度 O(log n)
- 有序遍历、范围查询
常用 API(范围/邻近)
- first/last
- ceiling/floor/higher/lower
- subSet/headSet/tailSet
示例
TreeSet<Integer> ts = new TreeSet<>();
ts.add(3); ts.add(1); ts.add(2);
int c = ts.ceiling(2); // 2
什么时候用
- 需要有序、范围查询(>=x 最小,<=x 最大)
性能
- O(log n)
5) Map(键值映射)
5.1 HashMap(最常用)
实现类型与原理
- 底层:哈希表数组 Node<K,V>[] table
- key -> hash() -> 桶下标(index)
- 桶内:链表(碰撞)或红黑树(JDK8+ 树化)
- 扩容:resize(通常成倍扩),rehash 分布到新桶
- 依赖 key 的 hashCode/equals
常用 API
- put, get, remove
- containsKey, getOrDefault
- putIfAbsent
- computeIfAbsent(懒加载/分组常用)
- merge(计数合并常用)
- 遍历:entrySet/keySet/values
示例(计数 + computeIfAbsent)
Map<String, Integer> cnt = new HashMap<>();
String x = "a";
cnt.put(x, cnt.getOrDefault(x, 0) + 1);
Map<String, List<Integer>> group = new HashMap<>();
group.computeIfAbsent("k", k -> new ArrayList<>()).add(42);
什么时候用
- 计数、映射、缓存、索引、分组(刷题最高频)
性能
- 平均 O(1)
- 扩容/rehash 会有一次性开销
- key 自定义对象要正确实现 equals/hashCode
5.2 LinkedHashMap(有序 Map,可做 LRU)
实现类型与原理
-
基于 HashMap + 双向链表
-
可选:
- 插入顺序(默认)
- 访问顺序(accessOrder=true)用于 LRU
-
重写 removeEldestEntry 可自动淘汰最老条目
示例(访问顺序)
LinkedHashMap<Integer,Integer> m = new LinkedHashMap<>(16, 0.75f, true);
m.put(1,1); m.put(2,2);
m.get(1); // 1 变“最近访问”
什么时候用
- 需要稳定遍历顺序
- LRU 缓存
性能
- 平均 O(1),略高开销
5.3 TreeMap(红黑树,有序 key)
实现类型与原理
- 红黑树存 key,按自然顺序或 comparator 排序
- 支持范围查询/邻近查询
常用 API
- firstKey/lastKey
- ceilingKey/floorKey/higherKey/lowerKey
- subMap/headMap/tailMap
示例
TreeMap<Integer,String> tm = new TreeMap<>();
tm.put(3,"c"); tm.put(1,"a"); tm.put(2,"b");
int k = tm.ceilingKey(2); // 2
什么时候用
- 需要有序 key、区间操作(时间线/区间合并)
性能
- O(log n)
5.4 ConcurrentHashMap(并发 Map,工程)
实现原理(高层)
- 分段锁(旧)-> JDK8+ 以 CAS + synchronized 在桶级别控制
- 目标:并发读写更高吞吐、避免全表锁
示例
Map<String,Integer> m = new java.util.concurrent.ConcurrentHashMap<>();
m.merge("a", 1, Integer::sum);
6) BitSet(位集合,状态压缩)
实现类型与原理
- 底层:long[](每个 long 64 位)
- 通过位运算 set/get/and/or,内存极省
常用 API
- set(i), clear(i), get(i)
- and/or/xor, flip(i)
- cardinality(), nextSetBit(i)
示例
BitSet bs = new BitSet();
bs.set(10);
boolean ok = bs.get(10);
什么时候用
- 大规模布尔标记、状态压缩 DP、位运算优化
性能
- 位运算快;空间比 boolean[] 更省(但可读性略差)
7) StringBuilder(可变字符串)
实现原理
- 底层:可扩容 char 数组(或 byte 数组,取决于 JDK 版本与编码实现)
- append 时容量不够会扩容并复制
常用 API
- append, insert, delete, reverse
- charAt, setCharAt, length
- toString
示例
StringBuilder sb = new StringBuilder();
sb.append("ab").append(123);
String s = sb.toString();
什么时候用
- 频繁拼接字符串(构造输出、路径、序列化)
性能
- 避免 String 多次 + 产生大量临时对象
8) 刷题常用“组合结构”(用现有结构模拟)
8.1 单调栈(ArrayDeque)
- 原理:维护栈内单调性,遇到破坏单调则弹出
- 用途:下一个更大元素、最大矩形、接雨水
Deque<Integer> st = new ArrayDeque<>();
for (int x : nums) {
while (!st.isEmpty() && st.peek() > x) st.pop();
st.push(x);
}
8.2 单调队列(滑窗最值)
- 原理:队列内维护候选下标单调,过期弹出
Deque<Integer> dq = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
while (!dq.isEmpty() && nums[dq.peekLast()] <= nums[i]) dq.pollLast();
dq.offerLast(i);
if (dq.peekFirst() <= i – k) dq.pollFirst();
if (i >= k – 1) ans[i – k + 1] = nums[dq.peekFirst()];
}
9) 性能选型对照
| 随机访问 + 尾插 | ArrayList | 动态数组/扩容 | get O(1), 中间插删 O(n) |
| 栈/队列/双端 | ArrayDeque | 环形数组 | 头尾 O(1) |
| TopK/最值流 | PriorityQueue | 二叉堆 | offer/poll O(log n) |
| 去重/判存在 | HashSet | 哈希表 | 平均 O(1) |
| 计数/映射 | HashMap | 哈希表 | 平均 O(1) |
| 有序/范围 | TreeSet/TreeMap | 红黑树 | O(log n) |
| 插入顺序稳定 | LinkedHash* | 哈希 + 双链表 | 平均 O(1) |
| 省空间布尔标记 | BitSet | long 位数组 | 位操作 |
10) 关键坑点
声明类型决定可用方法
- Queue q = new ArrayDeque<>(); 没有 push/pop
- Deque dq = new ArrayDeque<>(); 才有 push/pop
ArrayDeque 不允许 null(用 null 标记空槽)
HashMap/HashSet 的 key 必须正确实现 equals/hashCode
TreeMap/TreeSet 的 comparator 必须满足严格弱序,否则行为异常
PriorityQueue 默认小根堆;大根堆要 comparator
subList 是视图,修改会影响原 List


