Java 线性表、栈、队列和优先队列
Java 线性表、栈、队列和优先队列
选择合适的数据结构和算法是开发高性能软件的关键。数据结构是按特定形式组织数据的集合,不仅存储数据,还支持数据的访问与处理操作。
在面向对象思想中,数据结构被视为容器或容器对象,本质是一个类——通过数据域存储数据,提供查找、插入、删除等方法。创建数据结构即创建该类的实例,通过实例方法操作数据。
Java 提供了丰富的数据结构,统称为 Java 集合框架(Java Collections Framework),核心是 Collection 接口,为线性表、栈、队列、优先队列等定义了通用操作。
Java 集合框架概述
容器类型
Java 集合框架支持两类核心容器:
- 集合(Collection):存储元素集合,如线性表、栈、队列等。
- 映射表(Map):存储键/值(key/value)对,用于快速查找(本文暂不重点讨论)。
核心子接口与特性
| 接口/类 | 核心特性 |
|---|---|
List |
有序元素集合(插入顺序保留),可重复 |
Set |
无序元素集合,不可重复 |
Stack |
后进先出(LIFO) |
Queue |
先进先出(FIFO) |
PriorityQueue |
按优先级排序 |
设计原则
- 通用特性定义在接口中(如
Collection),具体实现封装在子类中。 - 接口间通过继承复用功能,子类按需实现接口方法,如果一个方法在子类中没有意义,可以按如下方式实现它。
pub1ic void someMethod() {
throw new UnsupportedOperationException("Method not supported");
}
Collection 接口与通用方法
Collection 是所有集合类的根接口,继承自 Iterable 接口,提供了集合操作的通用方法。
继承关系

核心方法
| 方法签名 | 功能描述 |
|---|---|
add(e: E): boolean |
向集合添加元素 e,成功返回 true |
addAll(c: Collection<? extends E>): boolean |
添加集合 c 中所有元素到当前集合 |
clear(): void |
清空集合所有元素 |
contains(o: Object): boolean |
判断集合是否包含元素 o |
containsAll(c: Collection<?>): boolean |
判断集合是否包含集合 c 中所有元素 |
isEmpty(): boolean |
判断集合是否为空 |
remove(o: Object): boolean |
从集合删除元素 o,成功返回 true |
removeAll(c: Collection<?>): boolean |
删除集合中所有存在于 c 中的元素(差集) |
retainAll(c: Collection<?>): boolean |
保留集合中与 c 共有的元素(交集) |
size(): int |
返回集合元素个数 |
toArray(): Object[] |
转换为 Object 数组返回 |
toArray(a: T[]): T[] |
转换为指定类型 T 的数组返回 |
iterator(): Iterator<E> |
获取集合的迭代器 |
forEach(action: Consumer<? super E>): void |
遍历集合,对每个元素执行 action 操作 |

集合运算说明
addAll:等价于集合的 并集 操作。removeAll:等价于集合的 差集 操作(删除当前集合在另一个集合中的元素)。retainAll:等价于集合的 交集 操作(仅保留两个集合的共同元素)。
基础使用示例
package com.collection;
import java.util.*;
/**
* @author Jing61
* Collection:集合
* List:线性表,存储有序的元素(插入有序)
* ArrayList:数组列表
* LinkedList:链表
* Set:集合,元素不重复
* HashSet:哈希集合(内部采用HashMap实现)
* LinkHashSet:插入有序
* TreeSet:树集合,默认排序
* Queue/Priority Queue/Deque:队列/优先队列/双端队列
*/
public class CollectionDemo {
public static void main(String[] args) {
// ArrayList
Collection<String> list1 = new ArrayList<>();
list1.add("hello world1");
list1.add("hello world2");
list1.add("hello world3");
// LinkedList
Collection<String> list2 = new LinkedList<>();
list2.add("hello world1");
list2.add("hello world3");
// 求并集
list2.addAll(list1);
// 删除
list2.remove("hello world1");
// 求差集
list1.removeAll(list2);
// 集合中是否包含某个元素
System.out.println(list2.contains("hello world1"));
// 集合中是否包含所有元素
System.out.println(list2.containsAll(list1));
// 删除所有元素
list1.clear();
// 求交集
System.out.println(list2.retainAll(list1));
// 迭代器
list2.forEach(s -> System.out.println(s));
// lambda 替换
list2.forEach(System.out::println);
// 优先队列
Queue<Integer> queue1 = new PriorityQueue<>();
queue1.add(1);
queue1.add(10);
queue1.add(5);
queue1.add(25);
queue1.add(15);
// 获取并删除优先级高的元素
System.out.println(queue1.poll());
// 获取当前对象的迭代器
Iterator<Integer> iterator = queue1.iterator();
while (iterator.hasNext()) { // 判断当前元素是否还有下一个元素
// 先得到当前元素,再迭代到下一个元素
System.out.println(iterator.next());
}
}
}
迭代器(Iterator)
所有实现 Collection 接口的集合都是可迭代的(Iterable),通过 iterator() 方法获取迭代器,用于遍历集合元素。
设计意义
迭代器是经典设计模式,无需暴露集合的底层存储细节(如数组、链表),即可统一遍历集合。
迭代器核心方法
| 方法签名 | 功能描述 |
|---|---|
hasNext(): boolean |
判断迭代器是否还有未遍历的元素 |
next(): E |
返回下一个元素,并将迭代器指针向后移动 |
迭代器使用示例
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 迭代器遍历示例
*/
public class TestCollection {
public static void main(String[] args) {
/*
* ArrayList:顺序表,底层数组存储
* 特点:地址连续、元素有序(插入顺序)、可重复
*/
ArrayList<String> names = new ArrayList<>();
names.add("PEPPA");
names.add("EMILY");
names.add("PEDRO");
names.add("SUZY");
System.out.println("小猪佩奇:");
System.out.println(names);
names.remove("PEDRO"); // 删除元素
System.out.println(names.size()); // 输出元素个数:3
Collection<String> collection = new ArrayList<>();
collection.add("danny");
collection.add("candy");
collection.add("rebbca");
System.out.println(collection);
collection.addAll(names); // 合并两个集合
// 迭代器遍历
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
线性表(List)
List 接口继承自 Collection,定义了有序、可重复的元素集合,支持按索引访问。核心实现类有 ArrayList 和 LinkedList。
ArrayList 与 LinkedList 对比
| 特性 | ArrayList(数组实现) | LinkedList(链表实现) |
|---|---|---|
| 底层存储 | 动态数组(容量不足时自动扩容) | 双向链表(节点存储元素和前后指针) |
随机访问效率(get(i)) |
高(O(1),直接通过索引定位) | 低(O(n),需从表头/表尾遍历到索引位置) |
| 表头插入/删除效率 | 低(O(n),需移动后续元素) | 高(O(1),仅需修改节点指针) |
| 中间/表尾插入/删除 | O(n)(需移动部分元素) | O(n)(需遍历到目标位置) |
| 遍历效率 | 迭代器/for循环均高效 | 仅迭代器高效(for循环通过 get(i) 遍历极慢) |
| 线程安全 | 不安全 | 不安全 |
性能测试示例
package com.collection;
import java.util.*;
/**
* @author Jing61
*/
public class ListDemo {
public static void main(String[] args) {
// 如果使用循环向ArrayList(默认创建的大小10)添加100万数据,会发生什么?
// 会扩容20次左右,可以提取给数组创建大小
List<Integer> list1 = new ArrayList<>(1000000);
Random random = new Random();
for (int i = 0; i < 1000000; i++) {
list1.add(random.nextInt(1000000));
}
// 获取ArrayList的获取元素的时间
var begin = System.currentTimeMillis();
System.out.println("array list1 get:" + list1.get(500000));
var end = System.currentTimeMillis();
System.out.println("array list1 get time:" + (end - begin) + "ms");
List<Integer> list2 = new LinkedList<>();
for (int i = 0; i < 1000000; i++) {
list2.add(random.nextInt(1000000));
}
// 获取LinkedList的获取元素的时间
begin = System.currentTimeMillis();
System.out.println("link list2 get:" + list2.get(500000));
end = System.currentTimeMillis();
System.out.println("link list2 get time:" + (end - begin) + "ms");
//头部增删元素对比
begin = System.currentTimeMillis();
list1.add(0, 1000000);
end = System.currentTimeMillis();
System.out.println("array list1 add time:" + (end - begin) + "ms");
begin = System.currentTimeMillis();
list2.add(0, 1000000);
end = System.currentTimeMillis();
System.out.println("link list2 add time:" + (end - begin) + "ms");
// 遍历线性表元素对比
begin = System.currentTimeMillis();
for (int i = 0; i < list1.size(); i++) list1.get(i);
end = System.currentTimeMillis();
System.out.println("array list1 遍历:" + (end - begin) + "ms");
begin = System.currentTimeMillis();
// 非常耗时,不建议使用,应该使用迭代器
for (int i = 0; i < list2.size(); i++) list2.get(i);
end = System.currentTimeMillis();
System.out.println("link list2 遍历:" + (end - begin) + "ms");
// 使用迭代器对比
begin = System.currentTimeMillis();
for (Iterator<Integer> iterator = list1.iterator(); iterator.hasNext();) {
iterator.next();
}
end = System.currentTimeMillis();
System.out.println("array list1 迭代器:" + (end - begin) + "ms");
begin = System.currentTimeMillis();
for (Iterator<Integer> iterator = list2.iterator(); iterator.hasNext();) {
iterator.next();
}
end = System.currentTimeMillis();
System.out.println("link list2 迭代器:" + (end - begin) + "ms");
// foreach 隐式迭代器
list1.forEach(s -> System.out.println(s));
// lambda 替换
list2.forEach(System.out::println);
}
}
选型建议
- 需频繁随机访问(
get)、表尾插入删除:选ArrayList。 - 需频繁在表头插入删除、未知元素数量:选
LinkedList。 - 遍历
LinkedList时,优先使用迭代器或foreach,避免for循环 +get(i)。
比较器(Comparable 与 Comparator)
集合排序需元素支持比较,Java 提供两种比较方式:Comparable(自然排序)和 Comparator(定制排序)。
Comparable 接口(自然排序)
- 定义在元素类内部,重写实现
compareTo(T o)方法,指定元素的“自然顺序”。 - 适用于元素类固定排序规则的场景(如按数字大小、字符串字典序)。
示例:Circle 类按半径自然排序
Circle
package com.collection;
/**
* @author Jing61
*/
public class Circle implements Comparable<Circle>{
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea() {
return Math.PI * radius * radius;
}
@Override
public String toString() {
return "Circle[radius=" + radius + "]";
}
@Override
public int compareTo(Circle circle) {
return (int) (this.radius - circle.radius);
}
}
ComparatorTest
package com.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Jing61
*/
public class ComparatorTest {
public static void main(String[] args) {
List<Circle> list = new ArrayList<>();
list.add(new Circle(2));
list.add(new Circle(1));
list.add(new Circle(4));
list.add(new Circle(5));
list.add(new Circle(3));
// 对集合中的元素排序--自然排序,需要实现compareTo接口
Collections.sort(list);
for (Circle circle : list) {
System.out.println(circle);
}
}
}
Comparator 接口(定制排序)
- 定义在元素类外部,创建独立的比较器类,实现
compare(T o1, T o2)方法。 - 适用于元素类无法修改(如第三方类)、需灵活切换排序规则的场景。
示例:用 Comparator 定制 Circle 排序
Circle
package com.collection;
/**
* @author Jing61
*/
public class Circle{
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea() {
return Math.PI * radius * radius;
}
@Override
public String toString() {
return "Circle[radius=" + radius + "]";
}
}
ComparatorTest
package com.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author Jing61
*/
public class ComparatorTest {
public static void main(String[] args) {
List<Circle> list = new ArrayList<>();
list.add(new Circle(2));
list.add(new Circle(1));
list.add(new Circle(4));
list.add(new Circle(5));
list.add(new Circle(3));
Collections.sort(list, new Comparator<Circle>() {
@Override
public int compare(Circle c1, Circle c2) {
return Double.valueOf(c1.getRadius()).compareTo(c2.getRadius());
}
});
for (Circle circle : list) {
System.out.println(circle);
}
}
}
核心区别
| 对比维度 | Comparable | Comparator |
|---|---|---|
| 实现位置 | 元素类内部 | 元素类外部 |
| 方法名 | compareTo(T o) |
compare(T o1, T o2) |
| 灵活性 | 固定排序规则,无法修改 | 可创建多个比较器,灵活切换规则 |
| 适用场景 | 元素类可修改,排序规则固定 | 元素类不可修改,需动态调整排序规则 |
Collections 工具类(静态方法)
Collections 类提供了大量操作集合/线性表的静态方法,简化排序、查找、反转等操作。
线性表核心操作
| 方法签名 | 功能描述 |
|---|---|
sort(list: List) |
自然排序(依赖元素 Comparable 接口) |
sort(list: List, c: Comparator) |
定制排序(使用指定 Comparator) |
binarySearch(list: List, key: Object) |
二分查找(需先排序,自然排序) |
binarySearch(list: List, key: Object, c: Comparator) |
二分查找(定制排序) |
reverse(list: List) |
反转线性表元素顺序 |
reverseOrder(): Comparator |
返回逆序比较器(用于降序排序) |
shuffle(list: List) |
随机打乱线性表元素 |
copy(des: List, src: List) |
复制源线性表 src 到目标线性表 des |
nCopies(n: int, o: Object): List |
返回包含 n 个 o 副本的线性表 |
fill(list: List, o: Object) |
用元素 o 填充线性表(覆盖所有元素) |
集合核心操作
| 方法签名 | 功能描述 |
|---|---|
max(c: Collection) |
返回集合最大值(自然排序) |
max(c: Collection, c: Comparator) |
返回集合最大值(定制排序) |
min(c: Collection) |
返回集合最小值(自然排序) |
min(c: Collection, c: Comparator) |
返回集合最小值(定制排序) |
disjoint(c1: Collection, c2: Collection): boolean |
判断两个集合是否无交集(无共同元素) |
frequency(c: Collection, o: Object): int |
返回元素 o 在集合中出现的次数 |
使用示例
package com.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author Jing61
*/
public class CollectionsTest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(20);
list.add(3);
list.add(41);
list.add(5);
// 逆序排序
Comparator<Integer> comparator = Collections.reverseOrder();
Collections.sort(list, comparator);
System.out.println(list);
// 正序排序
Collections.sort(list);
System.out.println(list);
System.out.println(Collections.min(list));
System.out.println(Collections.max(list));
}
}
向量类(Vector)与栈类(Stack)
Java 集合框架是在 Java2 中引入的,Vector 和 Stack 是 JDK1.0 遗留类,继承自 AbstractList,与 ArrayList 功能相似,但支持线程安全。
Vector 类
- 底层是动态数组,与
ArrayList核心区别:线程安全(所有方法加synchronized锁)。 - 效率低于
ArrayList,适用于多线程环境下的线性表操作。
示例:Vector 使用
package com.collection;
import java.util.Vector;
/**
* @author Jing61
*/
public class VectorTest {
public static void main(String[] args) {
// Vector:向量,线程安全(synchronized)
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(0);
System.out.println(vector);
vector.remove(0);
System.out.println(vector);
}
}
Stack 类
- 继承自
Vector,实现后进先出(LIFO) 的栈结构。 - 核心方法封装了栈的操作,无需手动处理数组扩容。
核心方法
| 方法名 | 功能描述 |
|---|---|
empty(): boolean |
判断栈是否为空(等价于 isEmpty()) |
peek(): E |
获取栈顶元素,不删除 |
pop(): E |
获取并删除栈顶元素 |
push(E item) |
将元素压入栈顶 |
search(Object o): int |
查找元素 o,返回栈顶到该元素的距离(未找到返回 -1) |
继承关系

队列(Queue)与优先队列(PriorityQueue)
Queue 接口(先进先出 FIFO)
Queue 继承自 Collection,定义了队列的核心操作(插入、提取、检验),避免 Collection 的随机访问方法(如 add(int index))。
核心方法(两种行为:抛异常/返回特殊值)
| 操作类型 | 抛异常(队列满/空时) | 返回特殊值(队列满/空时) |
|---|---|---|
| 插入元素 | add(E e) |
offer(E e)(满返回 false) |
| 移除队头 | remove() |
poll()(空返回 null) |
| 查看队头 | element() |
peek()(空返回 null) |
双端队列(Deque)与 LinkedList
Deque接口继承自Queue,支持两端插入/删除(双端队列)。LinkedList实现了Deque接口,是队列的推荐实现类(两端操作效率高)。
Deque 新增核心方法
| 操作方向 | 插入元素 | 移除元素 |
|---|---|---|
| 队首 | addFirst(E e) |
removeFirst() |
| 队尾 | addLast(E e) |
removeLast() |
优先队列(PriorityQueue)
- 元素按优先级排序,访问时优先级最高的元素先出队(非 FIFO),如果几个元素拥有相同的最高优先级,则任意选择一个。
- 默认按元素自然顺序排序(最小值优先级最高),可通过
Comparator定制优先级,PriorityQueue(initialCapacity,comparator)。
队列综合示例
package com.collection;
import java.util.*;
/**
* @author Jing61
*/
public class QueueTest {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
queue.offer(20);
queue.offer(3);
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll()); // null
System.out.println(queue.poll()); // null
// 双端队列
Deque<Integer> deque = new LinkedList<>();
deque.addFirst(1);
deque.addLast(2);
deque.addFirst(3);
deque.addLast(4);
System.out.println(deque.pollFirst());
System.out.println(deque.pollLast());
System.out.println(deque.pollFirst());
System.out.println(deque.pollLast());
deque.addFirst(1);
deque.addLast(2);
deque.addFirst(3);
deque.addLast(4);
System.out.println(deque.pollFirst());
System.out.println(deque.pollFirst());
System.out.println(deque.pollFirst());
System.out.println(deque.pollFirst());
deque.addFirst(1);
deque.addLast(2);
deque.addFirst(3);
deque.addLast(4);
System.out.println(deque.removeFirst());
System.out.println(deque.removeFirst());
System.out.println(deque.removeLast());
System.out.println(deque.removeLast());
// 默认升序
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(1);
priorityQueue.offer(10);
priorityQueue.offer(5);
priorityQueue.offer(25);
priorityQueue.offer(15);
System.out.println(priorityQueue.poll()); // 1
// 改变优先级
PriorityQueue<Integer> priorityQueue1 = new PriorityQueue<>(Collections.reverseOrder());
priorityQueue1.offer(1);
priorityQueue1.offer(10);
priorityQueue1.offer(5);
priorityQueue1.offer(25);
priorityQueue1.offer(15);
System.out.println(priorityQueue1.poll()); // 25
}
}
选型建议
- 普通 FIFO 队列:用
LinkedList实现Queue。 - 需两端操作:用
LinkedList实现Deque。 - 按优先级处理元素:用
PriorityQueue(默认升序,可定制排序)。

浙公网安备 33010602011771号