Java集合是经典数据结构的封装实现:ArrayList基于动态数组(查O(1)、增删O(n)),LinkedList基于双向链表(增删O(1)、查O(n)),HashSet基于哈希表(去重、查O(1)),TreeSet基于红黑树(自动排序、操作O(log n))。

学Java数据结构与算法在集合中的体现,关键不是先背概念,而是从“用对集合”倒推它背后的结构和逻辑。集合类不是黑盒,每个常用实现类都对应一种经典数据结构,而它的行为(快或慢、有序或无序、能否去重)正是该结构特性的直接反映。
从集合行为反推底层结构
遇到一个集合类,先问三个问题:它怎么存数据?怎么查数据?怎么保证不重复或有序?答案就藏在结构里:
- ArrayList 查得快、中间增删慢 → 底层是数组:连续内存、靠索引随机访问 O(1),但插入/删除要搬动后面所有元素,平均 O(n)
- LinkedList 插删快、查得慢 → 底层是双向链表:节点靠指针连接,改指针就行 O(1),但找第5个元素得从头挨个跳 O(n)
- HashSet 能去重、不保证顺序、查得极快 → 底层是哈希表:用元素的 hashCode 定位桶位置,理想情况 O(1);重复靠 equals 判断,所以自定义类用 HashSet 必须重写这两个方法
- TreeSet 自动排序、查增删都是 log n → 底层是红黑树:一种自平衡二叉搜索树,天然支持有序遍历和范围操作(比如“找大于10且小于20的所有数”)
用典型场景驱动理解
脱离场景记结构容易忘,结合真实开发需求来练,印象更牢:
- 需要按添加顺序遍历,又想快速去重 → 选 LinkedHashSet(哈希表 + 双向链表,既快又保序)
- 频繁在队首/队尾增删,偶尔查中间 → 用 LinkedList 当双端队列(Deque),别硬套 List 接口
- 要统计词频(单词 → 出现次数)→ HashMap 是自然选择;如果还要按词频排序输出 → 先用 HashMap 统计,再转成 List 按 value 排序,或用 TreeMap(但注意 TreeMap 按 key 排,不是 value)
- 实现一个 LRU 缓存(最近最少使用)→ LinkedHashMap 的 accessOrder 模式,get 时自动把命中的项移到尾部,淘汰头节点即可
动手验证比死记复杂度更有效
光看 O(1)、O(n) 不如自己测一测。写两段小代码对比:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
- 往百万级 ArrayList 尾部 add 一万次 vs 往头部 add 一万次:后者明显卡顿,印证“中间/头部插入代价高”
- 用 HashSet 和 ArrayList 分别 contains 一个随机数,数据量越大,差距越明显 —— 这就是哈希查找和线性扫描的本质区别
- 把同一组整数分别放进 HashSet、TreeSet、LinkedHashSet,打印出来看顺序差异:无序、升序、插入序一目了然
算法练习紧扣集合操作
很多基础算法题本质就是在考你对集合特性的运用:
- “两数之和” → 一遍遍历 + HashMap 存值与下标,用 O(1) 查找替代暴力 O(n²)
- “存在重复元素” → 直接转 HashSet,比较 size 是否变小,一行解决
- “前 K 个高频元素” → 先用 HashMap 统计频次,再用 PriorityQueue(最小堆)维护 top-K,避免全排序
- “岛屿数量”(DFS/BFS)→ 遍历过程用 HashSet 或布尔数组记录已访问坐标,防止重复进入
结构决定行为,行为反映结构。每次用集合时多想半秒“它为什么这样设计”,比刷十道模板题更能建立直觉。

















