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 接口,提供了集合操作的通用方法。

继承关系

image

核心方法

方法签名 功能描述
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 操作

image

集合运算说明

  • 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,定义了有序、可重复的元素集合,支持按索引访问。核心实现类有 ArrayListLinkedList

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 中引入的,VectorStack 是 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)

继承关系

image

队列(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(默认升序,可定制排序)。
posted @ 2025-11-12 17:35  Jing61  阅读(10)  评论(0)    收藏  举报