Java集合框架:队列、Queue和Deque详解

news2024/9/21 16:25:44

目录

一、普通队列

1. 概念

2. Queue(Java集合框架的接口)

3. Queue中的方法

4. 方法使用演示

5. 队列的模拟实现

6. 顺序普通队列的缺点:

 二、循环队列

1. 循环队列也是一种数据结构。基于上述队列的缺点,此时就有了循环队列,如下图:

2. 是一个类似圆形的数组:

3. 所以此时有两个问题:   

4. 循环队列的实现:  (oj题链接:力扣)

三、双端队列(Deque)

1. 概念

2. 双端队列的使用

3. 面试题

两个队列实现一个栈:

两个队列实现一个栈:


前言

    队列是一种数据结构,在Java集合框架中,有对应的实现的接口,Queue是一个队列规范的接口,Deque是一个双端队列实现的接口,由于两个都是接口,所以是不能直接进行是实例化的,需要接口引用具体的类来进行实例化,所以底层可以是顺序表(数组),也可以是链表(单 / 双链表)。

一、普通队列

1. 概念

    队列:只可以在一段进行插入操作,在另一端进行删除操作的线性表,队列具有先进先出的特性,在插入操作的一端称作队尾,进行删除操作的一端称作队头。

 2. Queue(Java集合框架的接口)

     如上图:Queue(队列)是一个接口,底层是一个双向链表来实现的,所以Queue不能直接实例化一个对象,只能是接口引用一个具体类(LinkedList)的方式来实例化。

3. Queue中的方法

boolean offer(E  e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中的有效元素个数
boolean isEmpty()判断队列是否为空

4. 方法使用演示

public static void main(String[] args) {
        //尾插法和头部删除
        MyQueue queue = new MyQueue();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.peek());//1
        System.out.println(queue.poll());//1
        System.out.println(queue.peek());//2
        System.out.println(queue.isEmpty());//false
        System.out.println(queue.usedSize);//3
    }

5. 队列的模拟实现

     注:双向链表是最合适实现一个队列的,双向链表可以在尾部插入,也可以在尾部进行删除,因为每个节点都有前驱和后继节点,插入和删除的时间复杂度都是O(1),但是如果是单链表此时只能使用尾插法插入,使用头删法(在头部进行删除)时间复杂度才是O(1).

//单链表实现一个队列
public class MyQueue {
    static class Node {
        public int val;
        public Node next;
        public Node(int val) {
            this.val = val;
        }
    }
    public Node head;
    public Node last;
    public int usedSize;
    //入队
    public void offer(int val) {
        Node node = new Node(val);
        if (head == null) {
            head = node;
            last = node;
        }else {
            last.next = node;
            last = node;
        }
        usedSize++;
    }
    //出队
    public int poll() {
        if (isEmpty()) {
            throw new EmptyException("队列是空的!");
        }
        int ret = head.val;
        head = head.next;
        if (head == null) {
            last = null;//如果只有一个节点,那么last也要置空
        }
        usedSize--;
        return ret;
    }
    //判断队列是否为空
    public boolean isEmpty() {
        return usedSize == 0;
    }
    //获取队列队顶元素
    public int peek() {
        if (isEmpty()) {
            throw new EmptyException("队列是空的!");
        }
        return head.val;
    }
    //获取队列有效元素的个数
    public int getUsedSize() {
        return usedSize;
    }
}

6. 顺序普通队列的缺点:

    如下图:此时一个数组实现的顺序队列正在一边入队元素,一边出队元素,如果队列中的元素满了,此时元素再进行出队,但是后边的元素是入不进来的,虽然前面的格子空出来了,但是此时元素只能从队尾进入,队头出,可以看出,此时的队列的利用效率不是很高。

 二、循环队列

1. 循环队列也是一种数据结构。基于上述队列的缺点,此时就有了循环队列,如下图:

2. 是一个类似圆形的数组:

1. 有front指针和rear指针同时指向数组的0下标,入队元素就让rear指针往后走一个,之后出队元素时,就让front指针向后移动。

2. 当循环队列满了,此时rear指针可以往前走一步,到达0下标,然后继续入队元素。

3. 所以此时有两个问题:   

1. 当队列满,如何让rear指针指向0下标?

2. 当队列满时,rear = front;当队列为空时,rear = front,所以如何判断队列的空和满?

    1. 每次入队元素或者出队元素时,让 rear  =(rear + 1)% queue.size(),front =(front + 1)% queue.size(),而不是简单的rear++,front++,所以就可以让rear下标和front下标在走到最后一个位置时,再往后走一步就又到了0下标的位置。

    2. 通过浪费一个空间来区分队列的空和满,如果rear指针的下一个就是front(0下标),此时就认为队列为满,当rear = front时,此时队列为空。(或者使用usedSize来记录当前元素个数也可以)。

4. 循环队列的实现:  (oj题链接:力扣)

package Review;
//循环队列底层就是一个数组
//浪费掉最后一个空间来表示队列是否是满的
//就是每次都让rear往后走一步,之后进行判断如果rear的下一个位置就是0下标
//此时队列就是满的,如果front == rear,此时队列是空的
class MyCircularQueue {
    private int[] elem;
    private int front;//队列的头
    private int rear;//队列的尾
    public MyCircularQueue(int k){
        this.elem = new int[k+1];
    }
    public boolean enQueue(int value) {
        //1.检查队列是否是满的
        if (isFull()) {
            return false;
        }
        //2.入队元素,之后让rear引用往后走一步
        elem[rear] = value;
        rear = (rear + 1) % elem.length;
        return true;
    }
    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        //front++;
        front = (front + 1) % elem.length;
        return true;
    }
    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return elem[front];
    }
    public int Rear() {
        if (isEmpty()) return -1;
        //return elem[rear - 1];
        //此时还有一个问题需要注意,如果rear到了0下标,之后就数组越界了
        //数组是没有-1下标的,
        //也就是让rear返回数组的最后一个下标
        int index = (rear == 0) ? elem.length - 1 : rear - 1;
        return elem[index];
    }
    public boolean isFull() {
        return (rear + 1) % elem.length == front;
    }
    public boolean isEmpty() {
        return front == rear;
    }
}

三、双端队列(Deque)

1. 概念

    双端队列就是可以在两端都可以入队,也可以出队的队列,元素可以从队头入队和出队,也可以从队尾出队和入队。

2. 双端队列的使用

   (在实际使用中,Deque接口使用的是比较多的,栈和队列都可以使用该接口,这个接口中有栈的方法,也有队列的方法)

public static void main9(String[] args) {
        //底层是一个双向链表
        Deque<Integer> deque = new LinkedList<>();
        //数组实现的双端队列:底层就是一个数组
        Deque<Integer> deque1 = new ArrayDeque<>();
        //顺序的双端队列也可以当作栈来使用
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);//顺序的双端队列(底层是用数组来实现的)也提供了栈的相关的方法

    }
    public static void main8(String[] args) {
        //双端队列
        Deque<Integer> deque = new LinkedList<>();
        //普通队列
        //Queue中既有offer方法,也有add方法,add在无法添加一个元素时,会抛出一个异常
        //offer方法优于add方法,如果无法添加元素,offer方法不会抛出异常
        Queue<Integer> queue = new LinkedList<>();
        //链式栈  虽然是具体的类但是里面有栈的方法
        //LinkedList类中的方法是最多的,因为它实现了很多接口,此时一定会重写接口中的方法
        LinkedList<Integer> stack = new LinkedList<>();
        //双向链表
        List<Integer> list = new LinkedList<>();
        //其他的都是使用接口来引用的:只有接口中的方法
    }

3. 面试题

1. 用栈实现一个队列 (oj链接:力扣)思路:用两个栈才能实现一个队列,因为栈是先进后出,队列是先进先出;此时需要把栈中的全部元素入栈到第二个栈中,此时的栈顶元素就是出队的元素。
2. 用队列实现一个栈  (oj链接:力扣)思路:两个队列实现一个栈,”入栈“开始入到第一个队列中,之后入队就入到不为空的队列中,”出栈“就出到另一个队列中,出size-1个元素,最后剩下的一个元素就是要出栈的元素。

两个队列实现一个栈:

import java.util.LinkedList;
import java.util.Queue;
class MyStack2 {
    private Queue<Integer> qu1;
    private Queue<Integer> qu2;
    public MyStack2() {
        qu1 = new LinkedList<>();
        qu2 = new LinkedList<>();
    }
    public void push(int x) {
        if (!qu1.isEmpty()) {
            qu1.offer(x);
        }else if (!qu2.isEmpty()) {
            qu2.offer(x);
        }else {
            qu1.offer(x);
        }
    }
    public int pop() {
        if (empty()) {
            return -1;
        }
        if (!qu1.isEmpty()){
            //此时一定需要定义一个size来存放qu1的容量,如果直接将size
            //写进for循环中,size一直在改变,就会导致循环的次数减少
            int size = qu1.size();
            for (int i = 0; i < size-1; i++) {
                qu2.offer(qu1.poll());
            }
            return qu1.poll();
        }else {
            int size = qu2.size();
            for (int i = 0; i < size-1; i++) {
                qu1.offer(qu2.poll());
            }
            return qu2.poll();
        }
    }
    public int top() {
        if (empty()) return -1;
        if (!qu1.isEmpty()){
            //此时一定需要定义一个size来存放qu1的容量,如果直接将size
            //写进for循环中,size一直在改变,就会导致循环的次数减少
            int size = qu1.size();
            int val = -1;
            for (int i = 0; i < size; i++) {
                val = qu1.poll();
                qu2.offer(val);
            }
            return val;
        }else {
            int size = qu2.size();
            int val = -1;
            for (int i = 0; i < size; i++) {
                val = qu2.poll();
                qu1.offer(val);
            }
            return val;
        }
    }
    public boolean empty() {
        return qu1.isEmpty() && qu2.isEmpty();
    }
}

两个队列实现一个栈:

import java.util.Stack;
class MyQueue2 {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    public MyQueue2() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }
    public void push(int x) {
        stack1.push(x);
    }
    public int pop() {
        //前提是两个队列都不能是空的
        if (empty()) return -1;
        if (stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
    public int peek() {
        if (empty()) return -1;
        if (stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }
    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

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

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

相关文章

为什么我不建议你入行网络安全,因为99.9%的人都绕不过这三个坎

前言 我一个朋友老赵&#xff0c;老赵在一家大型互联网公司做高级网络安全工程师&#xff0c;从实习生到工程师整整呆了六年。去年他们公司为了缩减成本&#xff0c;做了裁员&#xff0c;他也在其中&#xff0c;取而代之的是一个只有三年工作经验的 “新人” … 老赵想着&…

Windows10下安装Oracle19c提示“无法将 **\** 安装用户添加到 ** 组“解决办法

问题描述 操作系统&#xff1a;window10 数据库版本&#xff1a;Oracle19c 本机在安装Oracle19c提示无法将 ZHOUQUAN\zhouquan 安装用户添加到 %2% 组。 问题原因 根据安装的对话框中的日志&#xff0c;找到并打开 日志报错信息&#xff1a; 信息: WindowsSecurityExcep…

时序预测 | Matlab实现INFO-ELM向量加权算法优化极限学习机时间序列预测

时序预测 | Matlab实现INFO-ELM向量加权算法优化极限学习机时间序列预测 目录 时序预测 | Matlab实现INFO-ELM向量加权算法优化极限学习机时间序列预测效果一览基本介绍程序设计学习总结参考资料 效果一览 基本介绍 Matlab实现INFO-ELM向量加权算法优化极限学习机时间序列预测 …

skywalking 源码

源码核心是SkyWalkingAgent 找到一堆插件&#xff0c;来对符合条件的类来代理 通过AbstractClassEnhancePluginDefine.define方法来。 如果有很多版本的插件&#xff0c;spring有2.0版本,3.0版本,4.0版。 具体使用哪个版本&#xff0c;看被增加的类使用的是哪个版本的spring …

vue基础--计算商品的总价格

计算商品的总价格&#xff1a; 1、在 父组件中 通过计算属性 动态把总价格计算出来&#xff0c; 2、通过 父向子传值&#xff0c;通过自定义属性&#xff0c;把值传给 子组件 父组件&#xff1a; 1、使用计算属性computed 计算总价格&#xff1a; 1.1、先用filter 过滤出 数…

Unity UGUI5——图集

一、Drawcall ​ 字面理解 DrawCall&#xff0c;就是绘制呼叫的意思&#xff0c;表示 CPU&#xff08;中央处理器&#xff09;通知 GPU&#xff08;图形处理器-显卡&#xff09; &#xff08;一&#xff09;DrawCall 概念 就是 CPU &#xff08;处理器&#xff09;准备好渲染…

基于Web的停车场管理系统(Java)

目录 一、系统介绍 1.开发的环境 2.本系统实现的功能 3.数据库用到的表 4.工程截图 二、系统展示 1、登录页面 2、首页 3、系统信息管理模块 4、车位信息管理模块 5、IC卡信息管理模块 ​编辑6、固定车主停车管理模块 7、临时车主停车管理模块 8、系统功能操作模块 …

unity3d:小地图UV,UGUIshader毒圈挖孔,缩圈

运行效果 场景中缩圈 小地图中挖孔 大地图中挖孔 小地图 方案1使用Mask 给了一个方形的mask组件&#xff0c;然后根据玩家位置计算出地图左下角的位置进行移动。这种实现方式虽然简单&#xff0c;但是会有两个问题&#xff1a; 1.Overdraw特别大&#xff0c;几乎很多时候会有…

【LLMs 入门实战 】Vicuna 模型学习与实战

UC伯克利学者联手CMU、斯坦福等&#xff0c;再次推出一个全新模型70亿/130亿参数的Vicuna&#xff0c;俗称「小羊驼」&#xff0c;小羊驼号称能达到GPT-4的90%性能。 欢迎使用小羊驼&#x1f999;环境搭建权重下载下载 Vicuna Weight下载 LLAMA Weight构建真正的 working weigh…

Lattice Planner从入门到放弃

Lattice Planner相关背景和更正式的公式推导可以直接参考其原始论文《Optimal Trajectory Generation for Dynamic Street Scenarios in a Frent Frame》&#xff08;ICRA 2010&#xff09;&#xff0c;本文侧重于Lattic planner理论和代码的结合。 1. Lattice Planner基本流程…

2023年6月GESP能力等级认证C++一级真题

2023-06 GESP一级真题 题数&#xff1a;27 分数&#xff1a;100 测试时长&#xff1a;60min 一、选择题(每题 2 分&#xff0c;共 30 分) 1.以下不属于计算机输入设备的有 (B ) 。&#xff08;2分&#xff09; A、键盘 B、音箱 C、鼠标 D、传感器 答案解析&#xff1…

如果你正在做AI测试,那么这十点你必须注意

AI是一个已经进入人类日常生活的新技术时代&#xff0c;例如Siri&#xff0c;Alexa语音接口等。通过大数据和数据科学实现数据存储的进步&#xff0c;使用户能够进行快速分析和数据检索。机器学习是一个新领域&#xff0c;机 AI是一个已经进入人类日常生活的新技术时代&#x…

今天我们来说说MySQL的缓存机制

原文链接&#xff1a;http://www.ibearzmblog.com/#/technology/info?id5770c555acd4302f81d86976c06e2319 前言 当我们向数据库服务器发送一条SQL的时候&#xff0c;但数据库收到后就会执行&#xff0c;但是如果在短时间内都执行同一条SQL&#xff0c;如果每次数据库都会执…

CUDA和显卡驱动以及pytorch版本的对应关系

1 支持CUDA 的GPU 支持 CUDA 的 NVIDIA Quadro 和 NVIDIA RTX CUDA GPU | NVIDIA Developer您的 GPU 计算能力 您是否正在寻找 GPU 的计算能力然后查看以下表格。您可以在这里了解更多 计算能力 。 NVIDIA GPU 为全球数百万台台式机笔记本电脑工作站和超级计算机提供动力加速…

《计算机网络——自顶向下方法》精炼——4.4.3-4.4.5

学习是终身的职业。在学习的道路上&#xff0c;谁想停下来就要落伍。 文章目录 UPnP因特网控制报文协议&#xff08;ICMP&#xff09;IPv6IPv6数据报格式IPv4到IPv6的变革 UPnP 通用即插即用&#xff08;UPnP&#xff09;提供了一种让外部网络的主机与NAT内主机交换数据的方式…

六十分之十七———低头拉车后的抬头看路

目录 前言&#xff1a;一、目标二、计划三、完成情况四、提升改进(最少3点)五、意外之喜(最少2点)六、总结 前言&#xff1a; 距离上次的月总已经过去四个多月时间了&#xff0c;这段时间里又是一次阶段性的下沉和突破&#xff0c;于是也就有了现在的总结。 此时还想将自己17…

未来10年,网络安全人才就业的黄金期

随着大数据、物联网、人工智能等新技术的发展&#xff0c;信息技术与经济社会各领域的融合也更加深入。网络攻击行为日趋复杂、黑客攻击行为组织性更强、针对手机无线终端的网络攻击日趋严重&#xff0c;近几年有关网络攻击和数据泄露的新闻层出不穷。因此&#xff0c;随着国家…

Planning-oriented Autonomous Driving 解析

abstract 现代自动驾驶系统通常是模块化的序列任务&#xff0c;这种方式很容易造成累积误差和任务协调不足&#xff0c;因此设计一个端到端架构&#xff0c;从全局的视角出发为agent的交互提供互补的特征提取。 introduction (a) Most industrial solutions deploy separate …

【QQ界面展示-获取监听到的通知的具体内容 Objective-C语言】

一、获取监听到的通知的具体内容 1.刚才这个没说啊,给大家补充一下, 我们看一下,刚才我们只说了一个通知的发布、和移除吧, 刚才我们这里,只是说了一个通知的发布、和移除吧, 以及监听, 那么,大家有没有发现, 我们一开始,给大家介绍的时候,是不是有两个对象啊,…

关于手机Camera的硬件电路知识

前阶段&#xff0c;小白教同事测了些Camere的基本功耗。正愁不知道写什么的小白&#xff0c;突然想到了素材&#xff0c;于是乎便趁着周末雷雨天宅家之际&#xff0c;写一篇关于手机Camere的硬件文章。 手机Camera 一、工作原理 关于Camera&#xff0c;景物通过镜头生成光学…