数据结构(Java):队列Queue集合力扣面试OJ题

1、队列

1.1 队列的概念

队列是一个特殊的线性表,只允许在一端(队尾)进行插入数据操作,在另一端(对头)进行删除数据。队列具有先进先出FIFO(First In First Out)的特性。

入队:数据只能从队尾进队列       出队:数据只能从对头出队列

即:队尾进队头出

我们可以把队列想象为一个排队的队伍,从队尾开始排队,排到了再从队头出队:

1.2 队列的设计

实现队列,我们可以使用单链表、双向链表、数组来实现。

  1. 单链表:我们可以使用last来作为标记尾结点的引用,入队时采用尾插法,出队时采用头删法,这样出队和入队时的时间复杂度都可以达到O(1)。注意:入队不可以采用头插法,因为出队时还需要找尾结点的前一个节点,时间复杂度必为O(n)。
  2. 双向链表:因为具有next和prev域,头插、尾插入队都是可以的,都为O(1)。
  3. 数组:普通的数组实现队列会产生很多空间的浪费,每当数据出队时,front前面的空间就会被浪费掉。我们可以设计循环队列来减少空间浪费。

接下来我们来聊一聊如何设计循环队列。

 1.2.1 循环队列

循环队列又叫做环形队列,通常是由数组实现的。

我们定义front和rear分别指向队头和队尾,rear的位置就是入队元素要插入的位置,起始时front和rear都在0下标处。

循环队列就是将数组的两端相连接,这样即使有元素出队,出队元素的位置,rear指针也可以达到,能够让新元素入队,减少空间的浪费。

当在rear为7下标时,进行入队操作后(假设队列不为满),rear要来到0下标的位置,那么要进行的操作是:rear == (rear+1)% len

于是更新rear的操作为:rear == (rear+1)% len

如果基于以上的设计,那么循环队列为空和队列为满时的条件均为:rear == front

那么对于循环队列,该如何进行判空和判满呢?我们给出改善设计:

判空:rear == front

判满(三种方法):

  1. 通过添加 size 属性记录(记录元素个数,size == 数组长度时为满)
  2.  浪费一个位置,判断rear的下一个是不是front。(front == (rear+1)% len时,说明队列满)
  3.  使用标记(在有元素的地方定义boolean类型为true,没有元素的地方定义为false,当front和rear相遇且boolean类型为true时,说明队列满)

1.2.2 实现循环队列

我们通过一道OJ题来设计循环队列。(使用浪费一个空间的方法来判满)

. - 力扣(LeetCode)

 代码:

class MyCircularQueue {
    public int front;
    public int rear;
    public int[] elem;

    public MyCircularQueue(int k) {
        //题目要求我们k个位置均能存储数据
        //因为我们使用浪费一个空间的方法来判满,所以我们这里要开辟k+1个空间
        elem = new int[k + 1];
    }
    
    public boolean enQueue(int value) {
        if(isFull()) {
            //不满时才能入队
            return false;
        }
        //在rear位置插入数据,并更新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;
       } 
       //front指向的位置就是队头元素
       return elem[front];
    }
    
    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        //当rear == 0时,需要做特殊处理
        //其余rear-1下标就是队尾元素的位置
        int index = rear == 0 ? elem.length - 1 : rear - 1;
        return elem[index];
    }
    
    public boolean isEmpty() {
        return rear == front;
    }
    
    public boolean isFull() {
        return (rear+1) % elem.length == front;
    }
}

2、队列Queue

在Java中,Queue是一个接口,底层是用链表来实现的:

注意:Queue是一个接口,在实例化时必须实例化实现Queue接口的类的对象。

2.1 Queue的方法

2.2、双端队列(Deque)

双端队列,元素可以在队头和队尾任意插入和删除元素,也就是说,元素可以从队头出队和入队,也可以从队尾出队和入队。

Java给出的双端队列Deque也是一个接口(Queue的扩展接口)在实例化时必须实例化实现Deque接口的类的对象。

2.3 使用Queue和Deque

在Java中,有多个类实现了Queue和Deque,这里我们只谈LinkedList和ArrayDeque。

我们可以使用LinkedList来实现队列和双端队列,为链式实现,底层为链表。

也可以使用ArrayDeque来实现队列和双端队列,为顺序实现,底层为数组。

同时,LinkedList和ArrayDeque中也实现了集合类Stack中的方法(Deque接口中包含了Stack的方法,而LinkedList和ArrayDeque实现了Deque接口),所以我们也可以使用LinkedList和ArrayDeque来实现栈。

注意:只有Deque接口中包含了Stack的方法,Queue接口没有包含。

也就是说,我们以后如果要构建栈、队列、双端队列...都可以通过LinkedList和ArrayDeque来实现,其方法更加丰富。


3、面试OJ题

3.1 用队列实现栈

. - 力扣(LeetCode)

3.1.1 思路分析

我们需要两个队列来模拟实现栈。

入栈:把数据放到不为空的队列当中,如果两个队列都为空,则随机放入即可。

出栈:两个队列必有一个为空,将不为空的队列中的size-1个元素移到空队列中,剩下的1个元素就是要模拟“出栈”的元素。

取栈顶元素:两个队列必有一个为空,将不为空的队列中的全部元素移到空队列中,并使用变量记录每次进新队列元素的数值,最后一次进队的元素就是“栈顶”元素。

 3.1.2 代码

class MyStack {
    Queue<Integer> qu1;
    Queue<Integer> qu2;

    public MyStack() {
        qu1 = new LinkedList<>();
        qu2 = new LinkedList<>();
    }
    
    //模拟入栈:把元素放到不为空的队列中
    public void push(int x) {
        if (empty()) {
            //两个队列都为空时 默认放到qu1中
            qu1.offer(x);
        } else if (qu1.isEmpty()) {
            qu2.offer(x);
        }else {
            qu1.offer(x);
        }
    }
    
    //将有元素的队列中的size-1个元素导入进空队列中
    //剩下的1个元素,就是要出栈的元素
    public int pop() {
        if (qu1.isEmpty()) {
            while (qu2.size() != 1) {
                int x = qu2.poll();
                qu1.offer(x);
            }
            return qu2.poll();
        }else {
            while (qu1.size() != 1) {
                int x = qu1.poll();
                qu2.offer(x);
            }
            return qu1.poll();
        }
    }
    
    //将有元素的队列中的全部元素导入进空队列中
    //并用变量记录每一次导进的元素,最后一次导入的元素就是栈顶元素
    public int top() {
        int x = 0;
        if (qu1.isEmpty()) {
            while (!qu2.isEmpty()) {
                x = qu2.poll();
                qu1.offer(x);
            }
            return x;
        }else {
            while (!qu1.isEmpty()) {
                x = qu1.poll();
                qu2.offer(x);
            }
            return x;
        }
    }
    
    //当两个队列都为空时,说明栈为空
    public boolean empty() {
        return qu1.isEmpty() && qu2.isEmpty();
    }
}

3.2 用栈实现队列

. - 力扣(LeetCode)

3.2.1 思路分析

模拟入队操作:“入队”的元素全部放入第一个栈中
模拟出队操作:
需要先判断第2个栈为不为空,
1.如果未空,需要把第一个栈当中的所有元素都放到第二个栈中,弹出第二个栈当中的栈顶元素
2.如果不为空,直接弹出第二个栈当中的栈顶元素

也就是说第二个栈的栈顶元素,其实就是我们所模拟队列的队头元素。

 3.2.2 代码

class MyQueue {

    ArrayDeque<Integer> stack1;//"入队"的元素统一放到stack1中
    ArrayDeque<Integer> stack2;//统一在stack2中出队

    public MyQueue() {
        stack1 = new ArrayDeque<>();
        stack2 = new ArrayDeque<>();
    }

    public void push(int x) {
        stack1.push(x);//"入队"的元素统一放到stack1中
    }

    public int pop() {
        if (stack2.isEmpty()) {
            //若stack2为空,则将stack1中的元素导入stack2中,
            // stack2的栈顶元素即为模拟出队的“队头”元素
            while (!stack1.isEmpty()) {
                int x = stack1.pop();
                stack2.push(x);
            }
            return stack2.pop();
        }else {
            //若stack2不为空,其栈顶元素即为模拟出队的“队头”元素
            return stack2.pop();
        }
    }

    public int peek() {
        if (stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                int x = stack1.pop();
                stack2.push(x);
            }
            return stack2.peek();
        }else {
            return stack2.peek();
        }
    }

    public boolean empty() {
        //当stack1和stack2均为空时,说明模拟的队列为空
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

OK~本次博客到这里就结束了,

感谢大家的阅读~欢迎大家在评论区交流问题~

如果博客出现错误可以提在评论区~

创作不易,请大家多多支持~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【密码学】密码学数学基础:群的定义

一、群的定义 在密码学中&#xff0c;群&#xff08;Group&#xff09;的概念是从抽象代数借用来的&#xff0c;它是一种数学结构&#xff0c;通常用于描述具有特定性质的运算集合。 群的定义 群定义中的几个关键要素&#xff1a; 集合&#xff1a;首先&#xff0c;群是由一系…

ES快速开发,ElasticsearchRestTemplate基本使用以及ELK快速部署

最近博主有一些elasticsearch的工作&#xff0c;所以更新的慢了些&#xff0c;现在就教大家快速入门&#xff0c;并对一些基本的查询、更新需求做一下示例&#xff0c;废话不多说开始&#xff1a; 1. ES快速上手 es下载&#xff1a;[https://elasticsearch.cn/download/]()这…

以数据编织,重构数据管理新范式

大数据产业创新服务媒体 ——聚焦数据 改变商业 人工智能几乎统一了全球最顶尖科技公司的认知&#xff1a;这个时代&#xff0c;除了AI&#xff0c;没有第二条路可走。 人工智能的技术逻辑颇有一种“暴力美学”&#xff0c;它依托于海量大数据和超高算力的训练和推理&#xff…

PE73_E6_BLE

PE73_E6_BLE 产品参数 产品型号 PE73_E6_BLE 尺寸(mm) 180*130*13mm 显示技术 电子墨水屏 显示区域(mm) 163.2(H) * 97.92(V) 分辨率(像素) 800*480 像素尺寸(mm) 0.204*0.204 显示颜色 黑/白/红/黄/橙/蓝/绿 视觉角度 180 工作温度 0-50℃ …

使用自制Qt工具配合mitmproxy进行网络调试

在软件开发和网络调试过程中&#xff0c;抓包工具是不可或缺的。传统的抓包工具如Fiddler或Charles Proxy通常需要设置系统代理&#xff0c;这会抓到其他应用程序的网络连接&#xff0c;需要设置繁琐的过滤&#xff0c;导致不必要的干扰。为了解决这个问题&#xff0c;我们可以…

调用第三方API超时如何区分是连接超时还是响应超时

在Java中调用第三方接口时&#xff0c;遇到超时问题通常涉及两种类型的超时&#xff1a;连接超时(Connect Timeout)和响应超时(Read TimeOut) 要查看是对方响应超时还是自己方连接超时&#xff0c;可以通过设置Java的HttpClient的超时时间和捕获异常来判断。以下是一个示例&…

灌区流量监测设备:农田灌溉的“智慧眼”

随着现代农业的不断发展&#xff0c;对灌溉技术的要求也越来越高。传统的灌溉方式不仅效率低下&#xff0c;而且容易造成水资源的浪费。如今&#xff0c;灌区流量监测设备以其独特的优势&#xff0c;成为农田灌溉的新宠&#xff0c;被誉为农田的“智慧眼”。 精准把控&#xff…

Java 实验五:继承与接口

一、实验目的 1、通过实验内容&#xff0c;锻炼自身进行需求分析&#xff0c;系统设计以及编程开发的能力&#xff0c;了解软件开发的流程。 二、实验环境 Jdk 1.8&#xff1b; Eclipse 三、实验内容 试分析停车场系统的常用业务功能&#xff0c;梳理出基本需求&#xff0…

优阅达线上分享:快速上手 Tableau 计算功能

无论是想获取更深入的业务洞察&#xff0c;还是希望实现更复杂的数据图表&#xff0c;Tableau 计算都能助你实现需求。然而&#xff0c;对于没有数学或统计经验的用户来说&#xff0c;快速理解并掌握 Tableau 计算功能的逻辑和用法并非易事。 如果你刚接触 Tableau 计算不知从…

把ros消息转换成中文输出

把ros消息转换成中文输出 c实现 发布 //发布性能评估数据 /trilateration_time_log void publishTrilaterationLog(const int reflectorPanelPoints_size,const double duration_count,const std::string& resultType,const std::string& resultChineseMessage,cons…

python基础知识点(蓝桥杯python科目个人复习计划69)

做些基础题 第一题&#xff1a;微生物增值 题目描述&#xff1a; 假设有两种微生物x和y。 x出生后每隔3分钟分裂一次&#xff08;数目加倍&#xff09;&#xff0c;y出生后每隔2分钟分裂一次&#xff08;数目加倍&#xff09;。 一个新出生的x&#xff0c;半分钟之后吃掉一…

Git常用命令以及使用IDEA集成Gitee

目录 一、设置用户签名 二、初始化本地库 三、查看本地库状态 四、添加文件到暂存区 五、提交本地库 六、修改文件 七、版本穿梭 八、Git分支 九、分支的操作 9.1、查看分支 9.2、创建分支 9.3、切换分支 9.4、合并分支 十、团队协作 十一、Idea集成Git 11.1、配…

初识C++|类与对象(上)

&#x1f36c; mooridy-CSDN博客 &#x1f9c1;C专栏&#xff08;更新中&#xff01;&#xff09; 1. 类的定义 1.1 类定义格式 • class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省略。 类体中内容…

【Web服务与Web应用开发】【C#】VS2019 创建ASP.NET Web应用程序,以使用WCF服务

目录 0.简介 1.环境 2.知识点 3.详细过程 1&#xff09;创建空项目 2&#xff09;添加Web表单 3&#xff09;使用Web表单的GUI设计 4&#xff09;添加服务引用 5&#xff09;在Web的button函数中调用服务&#xff0c;获取PI值 6&#xff09;测试 0.简介 本文属于一个…

如何直接套用模板,快速搭建一个3D展示页面?

随着Web3D技术的飞速进步&#xff0c;网页设计实现了从平面二维到立体三维的华丽蜕变&#xff0c;这一变革为品牌营销领域注入了前所未有的互动活力。多样化的3D营销手段&#xff0c;不仅极大地吸引了消费者的目光&#xff0c;还显著提升了品牌形象与销售量&#xff0c;助力企业…

各类专业技术的pdf电子书

从业多年&#xff0c;收集了海量的pdf电子书籍&#xff0c;感兴趣的私聊。

探索智慧校园德育系统的学生考核之道

在当代教育领域&#xff0c;智慧校园德育管理系统的学生考核功能正逐渐成为推动学生全面发展的重要引擎。它不仅革新了传统德育评价的方式&#xff0c;还深度融入了学生日常的学习生活&#xff0c;成为连接学生、教师与学校管理层之间沟通与理解的桥梁。德育考核功能的核心在于…

Excel办公技巧:制作二级联动下拉菜单

分享制作二级联动下拉菜单的方法&#xff0c;即使数据有增删&#xff0c;菜单也能自动更新&#xff01; 可以通过先定义名称&#xff0c;再结合数据验证&#xff0c;来做二级联动下拉菜单。 1. 准备数据 首先&#xff0c;我们需要准备好要进行二级联动下拉菜单的数据&#xff…

【大模型入门】LLM-AI大模型介绍

大语言模型 (LLM) 背景 &#x1f379;大语言模型 (Large Language Model) 是一种人工智能模型, 它们通常包含数千亿甚至更多的参数&#xff0c;并在大规模数据集上进行训练。大语言模型可以处理多种自然语言任务&#xff0c;如文本分类、问答、翻译、对话等等。 自然语言模型…

识别 TON 生态系统中前10种加密资产,以bitget 钱包为例

元描述&#xff1a;想要找到下一个 100 倍加密货币投资&#xff1f;请密切关注这篇文章&#xff1b;它揭示了所有可能很快变得非常有价值的 TON 网络宝石。 由 Telegram 提供支持的 TON&#xff08;开放网络&#xff09;生态系统正在蓬勃发展&#xff01;这是一个充满激动人心的…