深入理解Java数据结构
在Java中,“数据结构”的概念主要通过两种方式体现:一是内置的集合框架(JCF - Java Collections Framework),它提供了现成的、优化的数据结构实现;二是开发者可以利用语言特性(如数组、引用)自己构建所需的数据结构。理解这两者,是掌握Java编程的核心。
一、Java内置的集合框架
这是Java提供的、开箱即用的数据结构实现,位于 java.util
包中。它们都是接口和类的形式,是我们日常开发中最常使用的部分。
为了更直观地理解其庞大而清晰的体系,下图展示了JCF的核心接口与实现类的继承与实现关系:
1. 线性结构
数组 (Array):最基础、最高效的数据结构,支持随机访问。长度固定是其最大限制。
List (列表):有序、可重复的集合,弥补了数组长度固定的缺点。
ArrayList
:基于动态数组实现。查询快(O(1)),增删慢(需要移动元素,O(n))。LinkedList
:基于双向链表实现。增删快(尤其是在头尾,O(1)),查询慢(需要遍历,O(n))。同时实现了Deque
接口。Vector
:一个古老的、线程安全的动态数组实现。因性能差,已被Collections.synchronizedList()
和CopyOnWriteArrayList
取代。
2. 队列与栈
Queue (队列):先进先出 (FIFO) 的集合。
LinkedList
:可作队列使用。ArrayDeque
:基于循环数组实现的高效双端队列。性能通常优于LinkedList
,是实现队列和栈的首选。PriorityQueue
:优先级队列,基于堆(Heap) 实现。出队顺序按元素优先级(自然顺序或Comparator决定)。
Deque (双端队列):支持在两端插入和移除元素,既可作队列,也可作栈(LIFO)。
栈 (Stack):
Stack
类已不推荐使用。官方推荐使用Deque
接口及其实现(如ArrayDeque
)来模拟栈。
3. 键值对结构
Map (映射):存储键值对 (Key-Value),Key不允许重复。
HashMap
:基于哈希表实现。存取效率最高(O(1)),但无序。是最常用的Map。LinkedHashMap
:是HashMap
的子类,在哈希表基础上增加了双向链表,从而维护了元素的插入顺序或访问顺序。TreeMap
:基于红黑树实现。有序(Key按自然顺序或Comparator排序),存取效率为O(log n)。Hashtable
:古老的、线程安全的Map实现。已过时,被ConcurrentHashMap
取代。
4. 集合结构
Set (集):无序、不可重复的集合。其核心实现都是基于对应的Map(用Key来存储元素,Value是一个固定值)。
HashSet
:基于HashMap
实现,无序。LinkedHashSet
:基于LinkedHashMap
实现,维护插入顺序。TreeSet
:基于TreeMap
实现,有序。
二、利用语言特性自定义数据结构
虽然JCF非常强大,但有时我们需要实现一些特定的逻辑或结构。
1. 节点结构 (如链表、树)
使用类的自引用来构建。
// 定义单向链表节点
class ListNode {int val;ListNode next; // 指向下一个节点的引用ListNode(int x) { val = x; }
}// 定义二叉树节点
class TreeNode {int val;TreeNode left; // 左孩子引用TreeNode right; // 右孩子引用TreeNode(int x) { val = x; }
}
基于这种结构,可以实现各种复杂的链表、树、图等。
2. 数组的灵活运用
数组是构建更复杂结构的基础。
栈:可以用数组 + 一个指向栈顶的指针来实现。
堆 (Heap):通常用数组来模拟完全二叉树,从而实现优先队列。
并查集 (Union-Find):用数组来记录父节点,解决连接问题。
三、如何选择合适的数据结构?
选择的核心在于权衡,根据主要操作的需求来选择。
如果你的主要需求是... | 优先考虑... | 理由 |
---|---|---|
快速随机访问 | ArrayList , 数组 | 通过索引访问,时间复杂度O(1) |
频繁在头尾增删 | LinkedList , ArrayDeque | 链表操作O(1),ArrayDeque 性能也很高 |
需要去重 | HashSet | 基于哈希表,去重且查询快 |
需要键值对存取 | HashMap | 基于哈希表,存取效率O(1) |
需要元素有序 | TreeSet , TreeMap | 基于红黑树,元素自动排序 |
需要顺序且要快 | LinkedHashSet , LinkedHashMap | 哈希表+链表,兼顾速度和顺序 |
实现先进先出队列 | ArrayDeque | 效率高,无容量限制 |
实现优先级处理 | PriorityQueue | 基于堆,按优先级出队 |
总结原则:
默认选择:
ArrayList
(List),HashMap
(Map),HashSet
(Set)。线程安全:上述集合都非线程安全。多线程环境下需使用
ConcurrentHashMap
,CopyOnWriteArrayList
等JUC包下的并发集合,或用Collections.synchronizedXXX()
包装。知其所以然:理解底层是数组、链表还是哈希表/红黑树,是做出正确选择的关键。