深入理解Java中的队列(Queue)

news2024/11/17 0:57:02

目录

一、什么是队列(Queue)?

二、队列中的常用方法

三、Java中的队列接口和实现类

1. LinkedList

2. ArrayDeque

3. PriorityQueue

四、队列的应用场景

1.消息队列

2.线程池任务调度

3.缓存淘汰策略

4.网络请求调度

5.广度优先搜索(BFS)

五、关于队列的题目

1.模拟排队

2.任务调度

3.循环队列

4.烫手山芋

5.队列重排


引言:

        在Java编程中,队列(Queue)是一种非常重要的数据结构,它具有先进先出(FIFO)的特性,常用于处理各种异步任务、事件驱动和线程间通信等场景。本文将深入介绍Java中队列的知识,并结合具体的示例进行详细说明。

一、什么是队列(Queue)?

        队列是一种线性数据结构,它的特点是先进先出。在队列中,元素的添加(入队)操作在队尾进行,而元素的移除(出队)操作则在队头进行。因此,队列可以被简单地描述为一个“先进先出”的容器。在Java中,队列接口继承自Collection接口,并提供了丰富的方法来操作队列中的元素。

二、队列中的常用方法

  1. add(E e) 和 offer(E e):添加元素到队列

    Queue<String> queue = new LinkedList<>();
    queue.add("A");
    queue.offer("B");
    // 队列中的元素:[A, B]
    
  2. remove() 和 poll():移除并返回队列头部的元素

    Queue<String> queue = new LinkedList<>();
    queue.add("A");
    queue.add("B");
    String headElement = queue.remove();
    // headElement 的值为 "A",队列中的元素:[B]
    
  3. element() 和 peek():获取队列头部的元素,但不移除

    Queue<String> queue = new LinkedList<>();
    queue.add("A");
    queue.add("B");
    String headElement = queue.element();
    // headElement 的值为 "A",队列中的元素:[A, B]
    
  4. isEmpty():检查队列是否为空

    Queue<String> queue = new LinkedList<>();
    boolean isEmpty = queue.isEmpty();
    // isEmpty 的值为 true
    
  5. size():返回队列中元素的个数

    Queue<String> queue = new LinkedList<>();
    queue.add("A");
    queue.add("B");
    int size = queue.size();
    // size 的值为 2
    
  6. clear():清空队列中的所有元素

    Queue<String> queue = new LinkedList<>();
    queue.add("A");
    queue.add("B");
    queue.clear();
    // 队列中的元素为空

三、Java中的队列接口和实现类

        Java提供了多种队列的实现类,其中最常用的包括LinkedList、ArrayDeque和PriorityQueue等。这些实现类都实现了Queue接口,并在不同的场景中拥有各自的优势。下面分别介绍这几种队列实现类的特点及使用方法。

1. LinkedList

        LinkedList是Java中常用的双向链表实现,它同时实现了List接口和Queue接口,因此可以被用作队列来进行元素的添加和移除操作。以下是一个简单的示例:

Queue<String> queue = new LinkedList<>();
queue.offer("a"); // 入队
queue.offer("b");
String element = queue.poll(); // 出队
System.out.println(element); // 输出:a

        在上面的示例中,我们使用LinkedList实现了一个队列,并通过offer()方法进行入队操作,通过poll()方法进行出队操作。

2. ArrayDeque

        ArrayDeque是一种基于数组的双端队列实现,它同样实现了Queue接口,并且在尾部添加和移除元素的操作具有较低的时间复杂度。以下是ArrayDeque的简单示例:

Queue<Integer> queue = new ArrayDeque<>();
queue.offer(1); // 入队
queue.offer(2);
int element = queue.poll(); // 出队
System.out.println(element); // 输出:1

        在这个示例中,我们使用ArrayDeque实现了一个整数队列,并进行了入队和出队的操作。

3. PriorityQueue

        PriorityQueue是一个基于优先级堆的无界优先级队列实现,它可以确保每次出队的元素都是队列中优先级最高的元素。以下是PriorityQueue的简单示例:

Queue<Integer> queue = new PriorityQueue<>();
queue.offer(5); // 入队
queue.offer(3);
int element = queue.poll(); // 出队
System.out.println(element); // 输出:3

        在上述示例中,我们使用PriorityQueue实现了一个整数队列,并通过offer()方法入队,通过poll()方法出队。需要注意的是,PriorityQueue会根据元素的自然顺序或者比较器来决定出队顺序。

四、队列的应用场景

1.消息队列

用于实现系统间的异步通信,可以将消息发送到队列中,然后由消费者从队列中取出进行处理。

示例:使用RabbitMQ、Kafka等消息队列实现订单处理系统,将订单消息发送到队列中,后台系统从队列中消费并处理订单。

2.线程池任务调度

用于按照顺序执行任务,通常使用队列来存储待执行的任务。

示例:使用Java的Executor框架创建线程池,将需要执行的任务添加到线程池的任务队列中,线程池按照队列中的顺序依次执行任务。

3.缓存淘汰策略

用于限制缓存的大小,当缓存满时,通过队列中的先进先出规则来淘汰最早添加的元素。

示例:使用LRU(最近最少使用)缓存淘汰算法,将不经常访问的数据移出缓存,保留最近访问的数据在缓存中。

4.网络请求调度

用于处理请求队列,按照先到先处理的顺序处理请求,实现请求的有序处理。

示例:Web服务器接收到多个客户端请求时,将请求放入请求队列,然后按照队列中的顺序依次处理请求。

5.广度优先搜索(BFS)

用于解决图和树等数据结构的搜索问题,通过队列来实现搜索的层级遍历。

示例:在无权图中找到两个节点之间的最短路径,使用广度优先搜索算法,使用队列来实现节点的层级遍历。

这些只是队列应用的一小部分示例,队列作为一种重要的数据结构,在计算机科学中被广泛应用。具体的应用场景根据问题的需求和实际情况选择合适的方法和数据结构。

五、关于队列的题目

1.模拟排队

        编写一个程序,使用队列模拟排队的情景。用户可以加入队列,处理队列中的人,并显示当前队列的状态。

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

public class QueueSimulation {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("请选择操作:1.加入队列 2.处理队列 3.显示队列状态 4.退出");
            int choice = scanner.nextInt();
            switch (choice) {
                case 1:
                    System.out.println("请输入加入队列的人名:");
                    String name = scanner.next();
                    queue.add(name);
                    System.out.println(name + " 加入了队列。");
                    break;
                case 2:
                    String processed = queue.poll();
                    if (processed != null) {
                        System.out.println(processed + " 被处理了。");
                    } else {
                        System.out.println("队列为空,无人可处理。");
                    }
                    break;
                case 3:
                    System.out.println("当前队列状态:" + queue);
                    break;
                case 4:
                    System.out.println("程序结束。");
                    return;
                default:
                    System.out.println("输入无效,请重新输入。");
                    break;
            }
        }
    }
}

        这个程序通过创建一个字符串类型的队列来模拟人员排队的情景。用户可以选择加入队列、处理队列中的人或者显示当前队列状态。运行程序后,按照提示输入数字选择操作即可体验队列的基本操作。 

2.任务调度

        设计一个任务调度器,要求按照优先级从高到低执行任务。每个任务都有一个优先级值,值越高优先级越高。

import java.util.PriorityQueue;

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

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

    public String getName() {
        return name;
    }

    public int getPriority() {
        return priority;
    }

    @Override
    public int compareTo(Task other) {
        return other.getPriority() - this.getPriority();
    }
}

public class TaskScheduler {
    public static void main(String[] args) {
        PriorityQueue<Task> queue = new PriorityQueue<>();
        queue.add(new Task("Task 1", 5));
        queue.add(new Task("Task 2", 3));
        queue.add(new Task("Task 3", 1));

        while (!queue.isEmpty()) {
            Task task = queue.poll();
            String name = task.getName();
            System.out.println("Executing task: " + name);
        }
    }
}

        在这个示例中,我们定义了一个 Task 类来表示任务,包含任务的名称和优先级。我们实现了 Comparable 接口,根据任务的优先级进行比较。

        在 TaskScheduler 类的 main 方法中,我们使用一个优先级队列 PriorityQueue 来存储任务。我们添加了三个带有不同优先级的任务到队列中。然后,我们从队列中不断取出任务并打印任务名称,直到队列为空。

        在这个示例中,任务的执行顺序将按照优先级从高到低进行。你可以根据需要修改任务的名称和优先级,并向队列中添加更多任务来进行测试。

3.循环队列

        实现一个循环队列,它有固定的容量,当队列已满时,新增的元素将替换队列头部的元素

public class CircularQueue {
    private int[] queue;
    private int front;
    private int rear;
    private int capacity;
    private int size;

    public CircularQueue(int capacity) {
        this.capacity = capacity;
        this.queue = new int[capacity];
        this.front = 0;
        this.rear = 0;
        this.size = 0;
    }

    public void enqueue(int item) {
        if (isFull()) {
            System.out.println("队列已满,执行替换操作: " + item);
            queue[rear] = item;
            rear = (rear + 1) % capacity;
            front = (front + 1) % capacity;
        } else {
            System.out.println("入队元素: " + item);
            queue[rear] = item;
            rear = (rear + 1) % capacity;
            size++;
        }
    }

    public int dequeue() {
        if (isEmpty()) {
            System.out.println("队列为空,无法出队。");
            return -1;
        } else {
            int item = queue[front];
            front = (front + 1) % capacity;
            size--;
            System.out.println("出队元素: " + item);
            return item;
        }
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean isFull() {
        return size == capacity;
    }

    public static void main(String[] args) {
        CircularQueue circularQueue = new CircularQueue(5);
        circularQueue.enqueue(1);
        circularQueue.enqueue(2);
        circularQueue.enqueue(3);
        circularQueue.enqueue(4);
        circularQueue.enqueue(5);
        circularQueue.enqueue(6); // 替换元素
        circularQueue.dequeue();
        circularQueue.dequeue();
        circularQueue.dequeue();
        circularQueue.dequeue();
        circularQueue.dequeue();
        circularQueue.dequeue(); // 队列为空
    }
}

        在这个示例中,我们创建了一个名为 CircularQueue 的类来表示循环队列,用一个固定大小的整型数组来存储队列元素。队列中的元素由 front 和 rear 指针来表示,front 指向队列头部,rear 指向队列尾部的下一个位置。

        在 enqueue 方法中,当队列已满时,我们执行替换操作。在 dequeue 方法中,我们从队列头部出队元素。同时,我们也提供了判断队列是否为空和队列是否已满的方法。

        在 main 方法中,我们展示了循环队列的基本使用方式:执行入队和出队操作,并观察替换元素和队列为空的情况。

4.烫手山芋

        在一个游戏中,玩家围成一个圈,手持一个山芋向左传递,每传递一定次数后,持芋者被淘汰。使用队列来模拟这个过程。

要使用队列来模拟烫手山芋游戏的过程,可以按照以下步骤进行操作:

  1. 创建一个队列来存储玩家的编号。
  2. 将所有玩家的编号依次加入队列中。
  3. 定义一个传递次数(如5次)来确定需要传递多少次后,持芋者被淘汰。
  4. 循环进行传递操作:将队首的玩家编号取出并加入队尾,重复指定的传递次数。
  5. 每次传递完成后,队首的玩家被淘汰,并从队列中移除。
  6. 重复进行步骤 4 和 5,直到队列中只剩下最后一个玩家为止。
  7. 最后剩下的玩家为胜利者。
import java.util.LinkedList;
import java.util.Queue;

public class HotPotatoGame {
    public static void main(String[] args) {
        int passCount = 5; // 传递次数
        String[] players = {"Alice", "Bob", "Charlie", "David", "Emma", "Frank"}; // 玩家姓名数组

        Queue<String> queue = new LinkedList<>();
        for (String player : players) {
            queue.add(player); // 将玩家加入队列
        }

        while (queue.size() > 1) {
            for (int i = 0; i < passCount - 1; i++) {
                String currentPlayer = queue.poll();
                queue.add(currentPlayer); // 将玩家传递指定次数后加回队列尾部
            }
            String eliminatedPlayer = queue.poll();
            System.out.println("玩家 " + eliminatedPlayer + " 被淘汰.");
        }

        String winner = queue.poll();
        System.out.println("胜利者是 " + winner + "!");
    }
}

        在这个示例中,我们使用了一个队列来模拟烫手山芋游戏。我们定义了传递次数 passCount 为 5,玩家数组 players 包含了参与游戏的所有玩家。

        在 main 方法中,我们首先创建了一个队列,并将所有玩家按顺序添加到队列中。

        然后,我们使用循环来模拟传递过程。每次循环前,我们将队首的玩家取出并加入队尾,重复执行传递次数减 1 次。当传递次数达到指定的次数后,当前队首的玩家被淘汰,并从队列中移除。

        最终,当队列中只剩下最后一个玩家时,他被宣布为胜利者。

5.队列重排

        给定一个队列,要求将队列中的元素按照特定规则重新排列。例如,将所有偶数放在队列前面,奇数放在队列后面。

        要将给定队列中的元素按照特定规则重新排列,可以使用一个辅助队列来实现。以下是一个示例实现,将偶数元素放在队列前面,奇数元素放在队列后面:

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

public class QueueReorder {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(1);
        queue.add(2);
        queue.add(3);
        queue.add(4);
        queue.add(5);

        Queue<Integer> reorderedQueue = reorderQueue(queue);

        System.out.println("重新排列后的队列:");
        while (!reorderedQueue.isEmpty()) {
            System.out.print(reorderedQueue.poll() + " ");
        }
    }

    public static Queue<Integer> reorderQueue(Queue<Integer> queue) {
        Queue<Integer> reorderedQueue = new LinkedList<>();
        Queue<Integer> oddQueue = new LinkedList<>(); // 奇数队列
        Queue<Integer> evenQueue = new LinkedList<>(); // 偶数队列

        // 将元素按照奇偶分别加入两个辅助队列
        while (!queue.isEmpty()) {
            int num = queue.poll();
            if (num % 2 == 0) {
                evenQueue.add(num);
            } else {
                oddQueue.add(num);
            }
        }

        // 将偶数队列的元素加入重新排列后的队列
        while (!evenQueue.isEmpty()) {
            reorderedQueue.add(evenQueue.poll());
        }

        // 将奇数队列的元素加入重新排列后的队列
        while (!oddQueue.isEmpty()) {
            reorderedQueue.add(oddQueue.poll());
        }

        return reorderedQueue;
    }
}

        在这个示例中,我们首先创建了一个原始队列 queue,并向队列中添加了一些整数。

        然后,我们定义了三个辅助队列:reorderedQueue 用于存储重新排列后的队列,oddQueue 用于存储奇数元素,evenQueue 用于存储偶数元素。

        接下来,我们遍历原始队列,将元素按照奇偶分别加入到对应的辅助队列。

        最后,我们将偶数队列的元素依次加入 reorderedQueue,然后将奇数队列的元素依次加入 reorderedQueue

        最终,返回 reorderedQueue,即为重新排列后的队列。

总结:

        通过本文的介绍,我们深入了解了Java中队列的知识,并介绍了三种常用的队列实现类:LinkedList、ArrayDeque和PriorityQueue。队列作为一种重要的数据结构,在Java编程中具有广泛的应用场景,对于处理异步任务、事件驱动和多线程等问题有着重要的作用。希望本文对你加深对Java队列的理解有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1407792.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

肺癌相关文献6

第十四篇 Classification of lung adenocarcinoma based on stemness scores in bulk and single cell transcriptomes IF&#xff1a;6.0 中科院分区:2区 生物学WOS分区&#xff1a;Q1被引次数&#xff1a; 4 背景&#xff1a;癌细胞具有无限期自我更新和增殖的能力[2]。在一…

# [NOI2019] 斗主地 洛谷黑题题解

[NOI2019] 斗主地 题目背景 时限 4 秒 内存 512MB 题目描述 小 S 在和小 F 玩一个叫“斗地主”的游戏。 可怜的小 S 发现自己打牌并打不过小 F&#xff0c;所以他想要在洗牌环节动动手脚。 一副牌一共有 n n n 张牌&#xff0c;从上到下依次标号为 1 ∼ n 1 \sim n 1∼…

UV紫外激光打标机的优缺点是什么

​ UV紫外激光打标机具有以下优点&#xff1a; 1. 精度高&#xff1a;紫外激光打标机的光束质量好&#xff0c;聚焦光斑小&#xff0c;可以实现在各种材料上进行超精细打标。 2. 速度快&#xff1a;由于紫外激光的独特特性&#xff0c;打标速度非常快&#xff0c;提高了生产效…

23111 C++ day1

思维导图 提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求使用C风格字符串完成 #include <iostream> #include<array>using namespace std;int main() {int a0,A0,num0,space0,other0;array<char…

中国大模型迎来“95后” 百度奖学金发掘百位“未来AI技术领袖”

在人工智能掀起的科技革命和产业变革浪潮下&#xff0c;大模型成为最受关注的研究领域。1月22日&#xff0c;第十一届百度奖学金颁奖典礼在北京举行&#xff0c;来自全球顶尖高校及科研机构的10位“未来AI技术领袖”脱颖而出&#xff0c;他们平均年龄仅27岁&#xff0c;其中8人…

Oracle触发器简单应用示例

目录 一、应用描述 【1】、应用场景&#xff1a; 【2】、具体场景&#xff1a; 二、表结构介绍 【1】表名介绍&#xff1a; 【2】表结构&#xff1a; 三、设置触发器 一、应用描述 【1】、应用场景&#xff1a; 现有一张库存明细以及销售明细表&#xff0c;销售明细表发生…

python合并多个dict---合并多个字典值---字典值相加

文章目录 序多个dict同key值相加collection.Counter传参重载号 多个dict合并练习 序 主要是借助Counter、函数传参和运算符重载&#xff01;各有优劣&#xff01; 多个dict同key值相加 collection.Counter 借助collections.Counter&#xff0c;但是它只适用于值为整数或者小…

扭蛋机小程序开发,让扭蛋迷体验到扭蛋的趣味性

扭蛋机作为盲盒的前身&#xff0c;也是深受大众的欢迎&#xff0c;十几到几十不等的价格就可以让消费者体验到幸福感。扭蛋机具有价格低、性价比高的特点&#xff0c;扭蛋中的主题商品也都是经典热门动漫&#xff0c;具有较高的收藏价值&#xff0c;吸引了不少的扭蛋迷。 随着…

企业新闻稿怎么写?纯干货!

企业新闻稿是企业宣传的重要营销方式&#xff0c;新闻稿件的质量直接决定你的宣传效果&#xff0c;企业新闻稿怎么写&#xff0c;接下来伯乐网络传媒就来给大家分享一些企业新闻稿写作心得&#xff0c;纯干货&#xff0c;建议收藏起来慢慢看&#xff01; 一、企业新闻稿的组成要…

深入理解stressapptest

文章目录 一、概述二、安装2.1、源码编译安装2.2、命令行安装2.3、安装确认三、重要参数详解3.1、查询支持的参数3.2、参数说明 四、实例4.1、随机测试&#xff08;默认模式&#xff09;4.2、循环测试4.2、全内存测试 团队博客: 汽车电子社区 一、概述 stressapptest是一款免费…

Pytorch线性代数

1、加法运算 A torch.arange(20, dtypetorch.float32).reshape(5, 4) B A.clone() # 通过分配新内存&#xff0c;将A的一个副本分配给B A, A B# tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13.,…

【裁员潮】技术变革下的职业危机,程序员会有多大影响,又应该如何面对

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《技术变革下的裁员潮》 文章将以博主的角度进行讲述&#xff0c;理解和水平有限&#xff0c;不足之处&#xff0c;望指正。 目录 背景硬实力职业危机…

Python环境的安装和Pycharm的安装

Python环境的安装 英文版官网&#xff1a;Welcome to Python.org&#xff0c; 因为是外网&#xff0c;加载可能会很慢 首先呢&#xff0c;我们先去官网查找&#xff1a;Python中文网 官网&#xff0c;这个官网是中文版的&#xff0c;点进去之后是这个页面 然后点击下载&#…

【nowcoder】链表的回文结构

牛客题目链接 链表的回文结构 /* struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {} };*/ #include <cstdlib> // 建议大伙自己对照我的代码画下图&#xff0c;假设A链表是&#xff1a;1 2 3 2 1 class PalindromeList { publi…

消息队列RabbitMQ.02.交换机的讲解与使用

目录 RabbitMQ中交换机的基本概念与作用解析 交换机的作用&#xff1a; 交换机的类型&#xff1a; 直连交换机&#xff08;Direct Exchange&#xff09;&#xff1a; 将消息路由到与消息中的路由键&#xff08;Routing Key&#xff09;完全匹配的队列。 主题交换机&#x…

【计算机网络】UDP协议与TCP协议

文章目录 一、端口号1.什么是端口号2.端口号范围划分3.认识知名端口号(Well-Know Port Number)4.netstat5.pidof 二、UDP协议1.UDP协议端格式2.UDP的特点3.面向数据报4.UDP的缓冲区5.UDP使用注意事项6.基于UDP的应用层协议 三、TCP协议1.TCP协议段格式1.1理解封装解包和分用1.2…

数据结构(C语言版)代码实现(三)——单链表部分代码实现

目录 格式 头文件 宏定义 线性表的单链表存储结构 按位查找 插入元素 删除元素 头插法建立单链表 合并非递减单链表 其他基本操作 完整版 测试代码&#xff08;主函数&#xff09; 测试结果 格式 参考 2.3节 线性表的链式表示和实现 头文件 宏定义 #pragma onc…

安卓移动设备使用DS file文件管理工具远程访问本地群晖NAS文件

文章目录 1. 群晖安装Cpolar2. 创建TCP公网地址3. 远程访问群晖文件4. 固定TCP公网地址5. 固定TCP地址连接6. 结语 DS file 是一个由群晖公司开发的文件管理应用程序&#xff0c;主要用于浏览、访问和管理存储在群晖NAS&#xff08;网络附加存储&#xff09;中的文件。这个应用…

小模型也能COT

前两章我们分别介绍了COT的多种使用方法以及COT的影响因素。这一章更多面向应用&#xff0c;既现实场景中考虑成本和推理延时&#xff0c;大家还是希望能用6B的模型就不用100B的大模型。但是在思维链基础和进阶玩法中反复提到不论是few-shot还是zero-shot的思维链能力似乎都是1…

‘cnpm‘ 不是内部或外部命令,也不是可运行的程序

一、问题 昨天用npm 安装环境&#xff0c;实在太慢了&#xff0c;就想用cnpm&#xff0c;然后发现提示‘cnpm 不是内部或外部命令,也不是可运行的程序。 看了很多方法&#xff0c;选择了下面这个&#xff0c;运气好到爆棚&#xff0c;就直接可以用了。其他的方法暂未去了解。先…