编程自学指南:java程序设计开发,Java Queue 队列详解,理解队列的基本概念和特点, Java 中 Queue 接口及其常用实现类

编程自学指南:java程序设计开发,Java Queue 队列详解

一、课程信息

学习目标

  1. 理解队列的基本概念和特点。
  2. 掌握 Java 中 Queue 接口及其常用实现类(如 LinkedList、ArrayDeque)的使用方法。
  3. 学会使用队列解决实际问题,如任务调度、广度优先搜索等。
  4. 了解队列的应用场景和重要性。

课程重点

  1. 队列的先进先出(FIFO)特性。
  2. Queue 接口的常用方法。
  3. 不同队列实现类的特点和适用场景。

课程难点

  1. 理解队列在实际问题中的应用思路。
  2. 区分不同队列实现类的性能差异。

二、课程导入

生活中的队列场景

在生活中,我们经常会遇到队列的场景。比如在银行排队办理业务,先到的人先办理,后到的人需要在后面排队等待;在食堂打饭时,也是按照排队的顺序依次打饭。这些场景都体现了队列的先进先出(FIFO)特性。

编程中的队列需求

在 Java 编程中,队列也有很多应用场景。例如,在多线程编程中,线程池会使用队列来管理待执行的任务;在网络编程中,消息队列可以用来实现异步通信。使用队列可以有效地管理数据的顺序,确保任务按照一定的顺序执行。

示例代码引入

import java.util.LinkedList;
import java.util.Queue;

public class QueueIntroduction {
    public static void main(String[] args) {
        // 创建一个队列
        Queue<String> queue = new LinkedList<>();

        // 向队列中添加元素
        queue.add("Alice");
        queue.add("Bob");
        queue.add("Charlie");

        // 从队列中取出元素
        String firstPerson = queue.poll();
        System.out.println("First person in the queue: " + firstPerson);
    }
}

三、队列概述

定义

队列是一种特殊的线性数据结构,遵循先进先出(First In First Out,FIFO)的原则。队列有两个主要操作:入队(enqueue)和出队(dequeue)。入队操作将元素添加到队列的尾部,出队操作从队列的头部移除元素。

特点

  1. 先进先出(FIFO):最先进入队列的元素最先被取出。
  2. 有序性:队列中的元素按照入队的顺序排列。
  3. 双端操作:支持在队列的头部和尾部进行操作。

Java 中的 Queue 接口

Java 中的 Queue 接口是队列的抽象表示,它继承自 Collection 接口。Queue 接口定义了队列的基本操作方法,如 add()offer()remove()poll()element() 和 peek() 等。

常用实现类

  1. LinkedList:基于链表实现的队列,支持高效的插入和删除操作。
  2. ArrayDeque:基于数组实现的双端队列,支持高效的随机访问和双端操作。
  3. PriorityQueue:基于优先级堆实现的优先队列,元素按照优先级进行排序。

四、Queue 接口常用方法

入队方法

  1. add(E e):将指定的元素插入到队列的尾部。如果队列已满,则抛出 IllegalStateException 异常。
  2. offer(E e):将指定的元素插入到队列的尾部。如果队列已满,则返回 false,否则返回 true
import java.util.LinkedList;
import java.util.Queue;

public class QueueEnqueueExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();

        // 使用 add 方法入队
        queue.add("Apple");
        // 使用 offer 方法入队
        boolean result = queue.offer("Banana");
        System.out.println("Offer result: " + result);
    }
}

出队方法

  1. remove():移除并返回队列的头部元素。如果队列为空,则抛出 NoSuchElementException 异常。
  2. poll():移除并返回队列的头部元素。如果队列为空,则返回 null
import java.util.LinkedList;
import java.util.Queue;

public class QueueDequeueExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.add("Cat");
        queue.add("Dog");

        // 使用 remove 方法出队
        String removedElement = queue.remove();
        System.out.println("Removed element: " + removedElement);

        // 使用 poll 方法出队
        String polledElement = queue.poll();
        System.out.println("Polled element: " + polledElement);

        // 尝试从空队列中出队
        String emptyPoll = queue.poll();
        System.out.println("Empty poll result: " + emptyPoll);
    }
}

查看头部元素方法

  1. element():返回队列的头部元素,但不移除。如果队列为空,则抛出 NoSuchElementException 异常。
  2. peek():返回队列的头部元素,但不移除。如果队列为空,则返回 null
import java.util.LinkedList;
import java.util.Queue;

public class QueuePeekExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.add("Elephant");

        // 使用 element 方法查看头部元素
        String element = queue.element();
        System.out.println("Element: " + element);

        // 使用 peek 方法查看头部元素
        String peek = queue.peek();
        System.out.println("Peek: " + peek);

        // 清空队列后尝试查看头部元素
        queue.clear();
        String emptyPeek = queue.peek();
        System.out.println("Empty peek result: " + emptyPeek);
    }
}

方法对比总结

操作类型抛出异常返回特殊值
插入add(e)offer(e)
移除remove()poll()
查看element()peek()

五、LinkedList 作为队列的使用

内部实现原理

LinkedList 是一个双向链表,它实现了 Queue 接口。在使用 LinkedList 作为队列时,入队操作相当于在链表的尾部添加元素,出队操作相当于在链表的头部移除元素。

示例代码

import java.util.LinkedList;
import java.util.Queue;

public class LinkedListQueueExample {
    public static void main(String[] args) {
        // 创建一个使用 LinkedList 实现的队列
        Queue<String> queue = new LinkedList<>();

        // 入队操作
        queue.offer("Fish");
        queue.offer("Giraffe");

        // 遍历队列
        for (String element : queue) {
            System.out.println(element);
        }

        // 出队操作
        String firstElement = queue.poll();
        System.out.println("Polled element: " + firstElement);
    }
}

特点和适用场景

  • 特点:插入和删除操作效率高,支持双端操作。
  • 适用场景:适用于需要频繁进行插入和删除操作的场景,如任务调度、消息队列等。

六、ArrayDeque 作为队列的使用

内部实现原理

ArrayDeque 是基于数组实现的双端队列,它使用循环数组来存储元素。通过维护两个指针(头指针和尾指针)来实现队列的入队和出队操作。

示例代码

import java.util.ArrayDeque;
import java.util.Queue;

public class ArrayDequeQueueExample {
    public static void main(String[] args) {
        // 创建一个使用 ArrayDeque 实现的队列
        Queue<String> queue = new ArrayDeque<>();

        // 入队操作
        queue.offer("Horse");
        queue.offer("Iguana");

        // 查看队列大小
        int size = queue.size();
        System.out.println("Queue size: " + size);

        // 出队操作
        String firstElement = queue.poll();
        System.out.println("Polled element: " + firstElement);
    }
}

特点和适用场景

  • 特点:随机访问效率高,支持双端操作,性能优于 LinkedList
  • 适用场景:适用于需要频繁进行随机访问和双端操作的场景,如栈和队列的混合使用。

七、PriorityQueue 优先队列

内部实现原理

PriorityQueue 是基于优先级堆实现的优先队列,它使用堆数据结构来维护元素的优先级。堆是一种完全二叉树,每个节点的值都大于或等于其子节点的值(最大堆)或小于或等于其子节点的值(最小堆)。

示例代码

import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 创建一个优先队列
        Queue<Integer> priorityQueue = new PriorityQueue<>();

        // 入队操作
        priorityQueue.offer(3);
        priorityQueue.offer(1);
        priorityQueue.offer(2);

        // 出队操作,元素按优先级顺序出队
        while (!priorityQueue.isEmpty()) {
            System.out.println(priorityQueue.poll());
        }
    }
}

自定义优先级

可以通过传入自定义的 Comparator 来改变元素的优先级顺序。

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

public class CustomPriorityQueueExample {
    public static void main(String[] args) {
        // 自定义比较器,按年龄降序排序
        Comparator<Person> ageComparator = Comparator.comparingInt(p -> -p.age);

        // 创建一个使用自定义比较器的优先队列
        Queue<Person> personQueue = new PriorityQueue<>(ageComparator);

        // 入队操作
        personQueue.offer(new Person("Jack", 25));
        personQueue.offer(new Person("Jill", 20));
        personQueue.offer(new Person("John", 30));

        // 出队操作,元素按年龄降序出队
        while (!personQueue.isEmpty()) {
            System.out.println(personQueue.poll());
        }
    }
}

特点和适用场景

  • 特点:元素按照优先级顺序出队,插入和删除操作的时间复杂度为 O (log n)。
  • 适用场景:适用于需要根据元素的优先级进行排序和处理的场景,如任务调度、图算法等。

八、队列的实际应用案例

案例 1:任务调度

假设有一个任务队列,每个任务有不同的优先级。使用优先队列来管理这些任务,确保高优先级的任务先执行。

import java.util.PriorityQueue;
import java.util.Queue;

class Task implements Comparable<Task> {
    int priority;
    String name;

    public Task(int priority, String name) {
        this.priority = priority;
        this.name = name;
    }

    @Override
    public int compareTo(Task other) {
        return Integer.compare(other.priority, this.priority);
    }

    @Override
    public String toString() {
        return "Task{name='" + name + "', priority=" + priority + "}";
    }
}

public class TaskScheduler {
    public static void main(String[] args) {
        // 创建一个优先队列来管理任务
        Queue<Task> taskQueue = new PriorityQueue<>();

        // 添加任务到队列
        taskQueue.offer(new Task(3, "Task 3"));
        taskQueue.offer(new Task(1, "Task 1"));
        taskQueue.offer(new Task(2, "Task 2"));

        // 执行任务
        while (!taskQueue.isEmpty()) {
            Task task = taskQueue.poll();
            System.out.println("Executing task: " + task);
        }
    }
}

案例 2:广度优先搜索(BFS)

广度优先搜索是一种用于遍历或搜索树或图的算法,它使用队列来实现。

import java.util.*;

class Graph {
    private int V; // 顶点数
    private LinkedList<Integer>[] adj; // 邻接表

    public Graph(int v) {
        V = v;
        adj = new LinkedList[v];
        for (int i = 0; i < v; ++i)
            adj[i] = new LinkedList();
    }

    // 添加边
    public void addEdge(int v, int w) {
        adj[v].add(w);
    }

    // 广度优先搜索
    public void BFS(int s) {
        boolean[] visited = new boolean[V];
        Queue<Integer> queue = new LinkedList<>();

        visited[s] = true;
        queue.add(s);

        while (!queue.isEmpty()) {
            s = queue.poll();
            System.out.print(s + " ");

            Iterator<Integer> i = adj[s].listIterator();
            while (i.hasNext()) {
                int n = i.next();
                if (!visited[n]) {
                    visited[n] = true;
                    queue.add(n);
                }
            }
        }
    }
}

public class BFSTraversal {
    public static void main(String[] args) {
        Graph g = new Graph(4);

        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 2);
        g.addEdge(2, 0);
        g.addEdge(2, 3);
        g.addEdge(3, 3);

        System.out.println("Following is Breadth First Traversal " +
                "(starting from vertex 2)");

        g.BFS(2);
    }
}

九、课堂练习

练习 1

使用队列实现一个简单的消息队列,支持消息的入队和出队操作,并打印出队的消息。

import java.util.LinkedList;
import java.util.Queue;

public class MessageQueueExercise {
    public static void main(String[] args) {
        // 请完成代码
    }
}

练习 2

使用优先队列对一组学生对象按照成绩从高到低进行排序,并输出排序后的结果。

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

class Student {
    String name;
    int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{name='" + name + "', score=" + score + "}";
    }
}

public class StudentPriorityQueueExercise {
    public static void main(String[] args) {
        // 请完成代码
    }
}

十、课程总结

重点回顾

  1. 队列的基本概念和特点,特别是先进先出(FIFO)特性。
  2. Queue 接口的常用方法,包括入队、出队和查看头部元素的方法。
  3. 不同队列实现类(LinkedList、ArrayDeque、PriorityQueue)的特点和适用场景。
  4. 队列在实际问题中的应用,如任务调度和广度优先搜索。

注意事项

  1. 在使用队列时,要注意区分不同方法在队列为空或已满时的行为,避免抛出异常。
  2. 对于优先队列,要确保元素实现了 Comparable 接口或传入了自定义的 Comparator

十一、课后作业

作业 1

实现一个循环队列,支持入队、出队和查看队列大小的操作。

作业 2

使用队列实现一个简单的缓存系统,当缓存满时,按照先进先出的原则移除最早加入的元素。

作业 3

在广度优先搜索的基础上,实现一个最短路径算法,计算从起点到终点的最短路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zl515035644

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值