Java实现队列

news2024/12/26 2:27:05

目录

一、队列概述

二、队列的模拟实现 

1、入队 

2、出队 

3、取队头元素 

4、获取队列长度 

三、循环队列 

1、入队 

2、出队

3、取队头元素 

4、取队尾元素 

 四、面试题

1、用队列实现栈

2、用栈实现队列


一、队列概述

队列也是常见的数据结构,是一种线性数据结构,队列的主要特点:“先进后出”。

队列有队头和队尾,一般在队尾进行插入操作,队头进行删除操作。

二、队列的模拟实现 

在实现队列时可以使用链表也可以使用数组,但是链表的长度不受限制,不需要一段连续的空间,所以此处采用链表进行模拟实现。

在单链表进行模拟实现队列时,除了定义头结点外,还需要定义尾结点以确保在插入元素时时间复杂度为O(1),还定义一个usedSize来表示队列的长度。

1、入队 

在入队时首先应该判断队列是否为空,如果队列为空,就将head和last都指向新插入的结点;如果队列不为空,就将新插入的结点插入到last指向结点的后面。这两种情况都需要将队列的有效长度加1。

        //入队
        public void offer(int val){
            QNode qNode=new QNode(val);
            if(head==null){
                head=qNode;
                last=head;
            }else{
                last.next=qNode;
                last=qNode;
            }
            usedSize++;
        }

2、出队 

在出队列时,首先需要判断队列是否为空,若不为空,就取出head结点的值,将head后移,在此处也需要判断此时的head是否为null,若为null则也需要将last置为null,然后将队列的有效长度减一。

        //出队
        public int poll(){
            if(isEmpty()){
                System.out.println("队列为空");
                return -1;
            }else{
                int val=head.val;
                head=head.next;
                if(head==null){
                    last=head;
                }
                usedSize--;
                return val;
            }
        }
        //判断队列是否为空
        public boolean isEmpty(){
            if(usedSize==0){
                return true;
            }else{
                return false;
            }
        }

3、取队头元素 

若队列为空则无法获取,否则直接获取head的val值。

        //取队头元素
        public int peek(){
            if(head==null){
                return -1;
            }else{
                return head.val;
            }
        }

4、获取队列长度 

直接返回链表的有效长度即可。

        //获取队列的长度
        public int getSize(){
            return usedSize;
        }

三、循环队列 

为什么引入循环队列?

当队列用数组存储时,会造成极大的空间浪费。例如如下情况,rear队尾已达到数组的最大值,此时已无法存储元素,但是front队头之前还有空间却无法利用就会造成空间浪费。

循环队列:可以充分地利用空间,下面利用数组存储模拟实现循环队列。

 

1、入队 

在入队之前需要判断队列是否已满,可以定义一个usedSize来表示队列长度,还可以浪费一个空间,也就是rear指向队尾元素的下一个空间,用(rear+1)%数组长度==front来判断队列是否已满,前者比较简单就采用后者所示的方法进行实现,如下就表示队列已满。接着就在rear所指的位置插入元素,由于是循环队列,就让rear=(rear+1)%数组长度来进行后移。

public boolean isFull() {
        if((rear+1)%data.length==front){
            return true;
        }
        return false;
    }
public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }else{
           data[rear]=value;
           rear=(rear+1)%data.length;
           return true;
        }
    }

 2、出队

首先判断队列是否为空,若不为空则弹出front所指的元素,同样front=(front+1)%数组长度来实现后移。

public boolean isEmpty() {
        return rear==front;
    }
public boolean deQueue() {
        if(isEmpty()){
            return false;
        }else{
            front=(front+1)%data.length;
            return true;
        }

    }

3、取队头元素 

若队列不为空则直接取对头元素。

public int Front() {
        if(isEmpty()){
            return -1;
        }else{
            return data[front];
        }

    }

4、取队尾元素 

也需要先判断队列是否为空,还有由于rear指的是队尾元素的下一个空间,所以要对rear指向0进行特殊处理:返回数组长度-1位置的元素,其余情况返回rear-1位置的元素即可。

public int Rear() {
        if(isEmpty()){
            return -1;
        }else{
            if(rear==0){
                return data[data.length-1];
            }else{
                return  data[rear-1];
            }
        }

    }

 四、面试题

1、用队列实现栈

如果用一个队列来直接实现,栈是先进后出,队列是先进先出,在出栈时就无法只依靠一个队列来实现,所以就需要定义两个队列。

入栈:哪个队列不为空,就入哪个队列,如果都为空,就入第一个队列,因为要留一个队列用于出队列。

出栈:首先判断两个队列是否都为空,若都不为空则将不为空的队列出size-1个元素到为空的队列中,以确保不为空的队列中最后出队列的是最后进入的。

 取栈顶元素:与出栈类似,但是取栈顶元素需要将不为空的队列全部入到为空的队列,同时需要拿到最后一个出队的元素值。

public class MyStack2 {
    Queue<Integer> qu1;
    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()){
            int size=qu1.size()-1;
            for(int i=0;i<size;i++){
                qu2.offer(qu1.poll());
            }
            return qu1.poll();
        } else {
            int size = qu2.size() - 1;
            for (int i = 0; i < size; i++) {
                qu1.offer(qu2.poll());
            }
            return qu2.poll();
        }
    }

    public int top() {
        if(empty()){
            return -1;
        }
        if(!qu1.isEmpty()){
            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();
    }
}

 2、用栈实现队列

与上题类似,同样也需要两个栈来实现,但是一个栈主要进行去队列,另一个栈进行出队列,假设s1为入队栈,s2为出队栈。

入队:直接在s1进行入栈操作。

出队:如果s2不为空,就直接进行出栈,否则就将s1中的元素全部转移到s2中再进行出栈。

取队头元素:与出队操作类似,只不过将出栈换成取栈顶元素即可。

public class MyQueue2 {
    Stack<Integer> s1;
    Stack<Integer> s2;

    public MyQueue2() {
        s1=new Stack<>();
        s2=new Stack<>();
    }

    public void push(int x) {
        s1.push(x);
    }

    public int pop() {
        if(!s2.isEmpty()){
          return s2.pop();
        }else if(!s1.isEmpty()){
            int size=s1.size();
            for(int i=0;i<size;i++) {
                s2.push(s1.pop());
            }
            return s2.pop();
        }else{
            return -1;
        }
    }

    public int peek() {
        if(!s2.isEmpty()){
            return s2.peek();
        }else if(!s1.isEmpty()){
            int size=s1.size();
            for(int i=0;i<size;i++) {
                s2.push(s1.pop());
            }
            return s2.peek();
        }else{
            return -1;
        }
    }

    public boolean empty() {
        return s1.isEmpty()&&s2.isEmpty();
    }
}

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

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

相关文章

Mybatis源码解析二:DataSource数据源负责创建连接以及Transaction的事物管理

简介 对于一个成熟的ORM框架来说&#xff0c;数据源的管理以及事务的管理一定是不可或缺的组成&#xff0c;对于Mybatis来说&#xff0c;为了使用方便以及扩展简单也是做了一系列的封装&#xff0c;这一篇主要介绍mybatis是如何管理数据源以及事务的。 数据源DataSource Dat…

【深度学习】李宏毅2021/2022春深度学习课程笔记 - Adversarial Attack(恶意攻击)

文章目录一、基本概念1.1 动机1.2 恶意攻击的例子1.3 如何攻击&#xff1f;二、White Box vs Black Box三、One Pixel Attack四、Universal Adversarial Attack五、Beyond Image六、Attack in the Physical World七、Adversarial Reprogramming八、Backdoor in Model九、防御9.…

TLS回调函数实现反调试

title: TLS回调函数实现反调试.md date: 2022-06-16 23:40:49.231 updated: 2022-06-16 23:41:11.924 url: /archives/tls回调函数实现反调试 categories: tags: 逆向 TLS回调函数实现反调试 TLS-线程局部存储 先于我们OEP执行 #include<stdlib.h> #include<time.…

使用红黑树封装map、set

map、set如何用红黑树封装 map、set应用&#xff1a;map是一个使用参数K、参数V的类模板&#xff0c;set是只使用参数K的类模板。因为map应用时&#xff0c;需要使用到KV&#xff0c;而set只是存单个值&#xff0c;K。红黑树类的存储 &#xff1a;map和set类中使用红黑树数据成…

Logback配置详解

简介&#xff1a; logback是java的日志开源组件&#xff0c;是log4j创始人写的&#xff0c;性能比log4j要好&#xff0c;目前主要分为3个模块&#xff1a; logback-core:核心代码模块logback-classic:log4j的一个改良版本&#xff0c;同时实现了slf4j的接口&#xff0c;这样你…

树莓派mjpg-streamer实现监控功能

树莓派实现监控功能&#xff0c;调用mjpg-streamer库来实现。mjpg-streamer是一个开源的摄像头媒体流&#xff0c;通过本地获取摄像头的数据&#xff0c;通过http通讯发送&#xff0c;可以通过浏览器访问树莓派的IP地址和端口号就能看到视频流。 实现步骤 1.git clone https:…

关于内核的概念理解

狭义的操作系统可以认为就是内核&#xff0c;比如Linux内核。广义的操作系统则包括内核和一系列应用软件&#xff0c;比如Linux内核编辑器vim编译器gcc命令行解释器&#xff08;shell&#xff09;等&#xff0c;通常称为GNU/Linux。 源代码https://github.com/torvalds/Linux …

Jenkins自动化部署SpringBoot项目(windows环境)

文章目录1、Jenkins介绍1.1、概念1.2、优势1.3、Jenkins目的2、环境准备3、Jenkins下载3.1、下载3.2、运行3.3、问题解决4、Jenkins配置4.1、用户配置4.2、系统配置4.3、全局工具配置-最重要5、新建项目7、测试8、错误解决1、Jenkins介绍 1.1、概念 Jenkins是一个开源软件项目…

自动化测试Seleniums~1

一.什么是自动化测试 1.自动化测试介绍 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统&#xff0c;预设条件包括正常和异常&#xff0c;最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 将测试人员双手解放&#xff0c;将部分测…

黑马javaWeb Brand综合案例

01-综合案例-环境搭建 02-查询所有-后台&前台

leetcode83周赛

前言&#xff1a; 周赛两题选手,有点意思 830.较大分组的位置 思路&#xff1a;wa了三发&#xff0c;对边界了解的不够清楚 可以有一个小小的优化,时间复杂度O(n) // arr.add(start); //arr.add(i-1); //res.add(arr); res.add(Arrays.asList(start,i - 1));class Solution {pu…

MATLAB-mesh/ezmesh函数三维图形绘制

l ) mesh 函数生成由X、Y和Z指定的网线面&#xff0c;由C指定颜色的三维网格图。具体调用方法如下。mesh(Z):分别以矩阵Z的行、列下标作为x轴和y轴的自变量绘图。mesh(X , Y,Z):最常用的一般调用格式。mesh(X,Y ,Z,C):完整的调用格式&#xff0c;C用于指定图形的颜色&#xff0…

Ubuntu 20.4 美化桌面、美化引导界面、Mac 既视感

文章目录相关资源安装 gnome-tweaks安装浏览器插件方法一方法二&#xff08;推荐&#xff09;主题美化进行美化配置效果图美化前美化后美化 Dock扩展推荐引导美化安装主题修改配置相关资源 https://pan.baidu.com/s/1D7ZfzVKMmeZPAzuDDAVUbg提取码&#xff1a;ws3f 安装 gnom…

Java基础学习笔记(十)—— 包装类与泛型

包装类与泛型1 包装类1.1 基本类型包装类1.2 Integer类1.3 自动装箱 / 拆箱2 泛型2.1 泛型概述2.2 泛型的用法2.3 类型通配符1 包装类 1.1 基本类型包装类 基本类型包装类的作用 将基本数据类型封装成对象 的好处在于可以在对象中定义更多的功能方法操作该数据 public stat…

C库函数:stdlib.h

stdlib.h C 标准库 – <stdlib.h> | 菜鸟教程 (runoob.com) 该库主要涉及“字符串和其他类型数据的转换”、“内存空间的申请和释放”、“查找和排序”、随机数等功能函数。 7void *calloc(size_t nitems, size_t size) 分配所需的内存空间&#xff0c;并返回一个指向它…

大幅度减少零样本学习所需的人工标注

零样本旨在模仿人类的推理过程&#xff0c;利用可见类别的知识&#xff0c;对没有训练的样本不可见类别进行识别&#xff0c; 类别嵌入&#xff1a;Class embedding&#xff1a; 描述类别语义和视觉特征的向量&#xff0c;能够实现知识在类别间的转移&#xff0c;因而在零样本…

Web进阶:Day2 空间转换、动画

Web进阶&#xff1a;Day2 Date: January 4, 2023 Summary: 空间转换、动画 空间转换 **空间&#xff1a;**是从坐标轴角度定义的。 x 、y 和z三条坐标轴构成了一个立体空间&#xff0c;z轴位置与视线方向相同 空间转换也叫3D转换 属性&#xff1a;transform 语法&#xff1…

SolidWorks二次开发 API-获取当前语言与重命名文件

新的一年了&#xff0c;开始新的分享。 做SolidWorks二次开发的时候&#xff0c;难免会遇到多语言的问题。 针对不同语言的客户生成不同语言的菜单&#xff0c;所以我们要知道Solidworks的当前界面语言是什么。 这个就简单的说一下方法: GetCurrentLanguage 看结果&#xff1a;…

二、MySQL进阶教程

mysql高级 1&#xff0c;约束 上面表中可以看到表中数据存在一些问题&#xff1a; id 列一般是用标示数据的唯一性的&#xff0c;而上述表中的id为1的有三条数据&#xff0c;并且 马花疼 没有id进行标示 柳白 这条数据的age列的数据是3000&#xff0c;而人也不可能活到3000岁…

Curator实现分布式锁(可重入 不可重入 读写 联锁 信号量 栅栏 计数器)

文章目录前言代码实践1. 配置2. 可重入锁InterProcessMutex3. 不可重入锁InterProcessSemaphoreMutex4. 可重入读写锁InterProcessReadWriteLock5. 联锁InterProcessMultiLock6. 信号量InterProcessSemaphoreV27. 栅栏barrier8. 共享计数器8.1. SharedCount8.2. DistributedAto…