当前位置: 首页 > news >正文

接10月12日---队列笔记

上一篇说还有两道例题这里给大家补上

一. 栈的部分补充例题

1.逆波兰表达式

150. 逆波兰表达式求值 - 力扣(LeetCode)

1.1 题目描述:

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。
1.2 题解:

遍历字符,判断是否是数字字符,将其转为数字(Inter.parseInt())如果是运算符就弹出栈的两个元素进行运算

1.3 代码实现:
public int evalRPN(String[] tokens) {//定义一个栈Stack<Integer> stack = new Stack<>();//1.遍历for (int i = 0; i < tokens.length; i++) {String str = tokens[i];//如果是数字,就入栈if(isInteger(str)) {//要将字符转换为数字stack.push(Integer.parseInt(str));}else {int num1 = stack.pop();int num2 = stack.pop();//分字符运算switch (str) {case "+" :stack.push(num2 + num1);break;case "-":stack.push(num2 - num1);break;case "*":stack.push(num2 * num1);break;case "/":stack.push(num2 / num1);break;}}}return stack.peek();}public static boolean isInteger(String str) {//判断字符是否是运算符if(str.equals("+") ||str.equals("*")||str.equals("-") ||str.equals("/")) {return false;}return true;}
1.4(拓展知识点)后缀表达式   

后缀表达式(逆波兰式)是一种计算机高效处理的表达式形式,其运算符位于操作数之后,无需括号和优先级判断‌。以下是关键要点:

1. ‌基本概念‌

  • ‌定义‌:形如 a b c - d * +,等价于中缀表达式 a + ((b - c) * d)‌。

  • ‌特点‌:

    • 运算符顺序决定计算顺序,无需括号‌。

    • 适合栈结构计算,时间复杂度为O(n)。

2. ‌转换规则(中缀→后缀)‌

  • ‌操作数‌:直接输出。

  • ‌运算符‌:与栈顶比较优先级,高则压栈,低则弹出‌1。

  • ‌括号‌:(直接压栈)弹出至(‌。

‌示例‌:a + (b - c) * d → a b c - d * +‌。

3. ‌后缀表达式求值‌

  • ‌步骤‌:

    1. 初始化栈,扫描表达式。

    2. 遇到操作数压栈,遇到运算符则弹出两操作数运算,结果压栈。

    3. 最终栈顶为结果。

4.中缀表达式转后缀表达式:1.每个运算都加上括号,2.把对应运算符移到括号外面,3.把括号去掉 

2 .最小栈问题:

155. 最小栈 - 力扣(LeetCode)

2.1 题目描述:

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。
2.2 题解:(借助两个栈)

入栈:1)每次存放元素时,都要和最小栈的栈顶元素进行比较(<=)

           2)如果最小栈第一次存放的时候是空的,那么直接存储

出栈:1)每次出栈时,都要判断最小栈的栈顶元素,如果相同,最小栈也得出栈

2.3 代码实现:
Stack<Integer> stack;Stack<Integer> minStack;public MinStack() {//2.初始化栈stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {//1.入栈stack.push(val);//2.如果最小栈为空,就直接入栈if(minStack.empty()) {minStack.push(val);}else {//如果stack的栈顶值比最小栈的栈顶元素值小就入栈if(stack.peek() <= minStack.peek()) {minStack.push(stack.peek());}}}public void pop() {//判空if(stack.empty()) {return;}int val = stack.pop();//如果刚好出到和最小栈栈顶元素相同的值,最小栈也要出栈if(minStack.peek() == val) {minStack.pop();}}//相当于peek()public int top() {return stack.peek();}public int getMin() {return minStack.peek();}

其实这题不难,可以去试试。

接下来我们进入队列的学习

二. 队列(Queue)

1.介绍:

Java中的队列(Queue)是一种遵循先进先出(FIFO)原则的线性数据结构,常用于任务调度、消息传递等场景。以下是核心要点:

2.基本概念与操作

  1. ‌FIFO原则‌:元素从队尾(rear)插入,从队头(front)移除,确保最早入队的元素最先被处理。

  2. ‌核心操作‌:

    • enqueue(入队):添加元素到队尾,如offer(E e)add(E e)

    • dequeue(出队):移除并返回队头元素,如poll()remove()

    • peek():查看队头元素但不移除

  3. 常用的方法:插入:offer()  /  add();删除:poll()  /  remove();查看队头元素:peek()  /  element()

  4. add/offer和poll/remove的区别(扩展知识)

在Java的Queue接口中,add/offer和poll/remove是两组功能相似但行为不同的方法,主要区别体现在异常处理和返回值策略上:

add()与offer()的区别

  1. ‌异常处理‌
    add()在队列满时会抛出IllegalStateException,而offer()会返回false。这种设计使得offer()更适合容量受限的队列场景,避免程序因异常中断。

  2. ‌语义差异‌
    add()继承自Collection接口,强调集合操作的通用性;offer()是Queue专有方法,更符合队列插入的特定语义。

  3. ‌使用建议‌
    推荐优先使用offer(),因其通过返回值而非异常处理失败情况,代码健壮性更强。

poll()与remove()的区别

  1. ‌空队列行为‌
    remove()在队列为空时抛出NoSuchElementException,而poll()返回null,后者更适用于需要静默处理的场景。

  2. ‌方法来源‌
    remove()来自Collection接口,poll()是Queue的专属方法,专为队列的头部操作设计。

  3. ‌应用选择‌
    若需明确感知空队列状态(如关键业务流程),使用remove();若允许静默失败(如任务调度),选择poll()。

这两组方法体现了Queue接口“双策略”设计:一组通过异常反馈问题(add/remove),另一组通过返回值处理(offer/poll),开发者可根据具体容错需求选择

3.核心方法的实现:

        我这里是自己用双向链表来实现队列,用其他也可以,自己实现一遍可以增加对这个方法的理解。这里根据队列的性质,我们可以知道,入队是尾插,出队是头删,按这个逻辑很容易实现,要记得判空就行。

public class MyQueue {static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}//头和尾public ListNode first;public ListNode last;//1.入队(先进先出)尾插法:public void offer(int val) {ListNode node = new ListNode(val);//判空if(first == null) {first = node;last = node;}//尾插last.next = node;node.prev = last;last = node;}//2.出队(先出)头删public int poll() {//判空if(first == null) {//定义异常throw new EmptyException("队列为空!!");}int val = first.val;//只有一个结点if(first == last) {first = null;last = null;}else {first = first.next;first.prev = null;}return val;}//peek()public int peek() {if (first == null) {throw new EmptyException("队列为空!!");}return first.val;}//3.size()public int size() {ListNode cur = first;int count = 0;while(cur != null) {count++;cur = cur.next;}return count;}//emptypublic boolean empty() {return first == null;}
}

3.循环队列(特殊点和难点)

3.1 基本介绍

        Java中的循环队列是一种通过数组实现的队列结构,通过模运算实现存储空间的首尾循环利用,解决了顺序队列的"假溢出"问题。其核心特性是通过front和rear指针的环形移动实现高效的元素存取,并通过保留一个空位或size属性来区分队空和队满状态。如下图:

3.2 核心实现要点
  1. ‌指针计算‌
    入队时rear指针通过(rear + 1) % capacity移动,出队时front指针同理,确保指针到达数组末尾后回到起始位置。这种设计使得数组空间利用率达到100%。

  2. ‌状态判断‌

    • 队空条件:front == rear

    • 队满条件:(rear + 1) % capacity == front(保留一个空位方案)或通过size属性记录元素数量。

  3. ‌动态扩容‌
    当队列满时需扩容,通常将数组长度翻倍并重新排列元素(front到rear之间的连续段)

3.3 上手实践(用数组实现循环队列)

在循环队列中,我们主要要解决两个疑问:

1)rear 从 7 下标到 0 下标的操作,可以通过取模运算实现指针的循环移动。当rear指针到达数组末尾时(如下标7),执行rear = (rear + 1) % capacity即可使其回到0下标。

2)我们判断队列是满还是空的依据

  • 队列空的条件‌:front == rear,表示无有效元素。

  • ‌队列满的条件‌:牺牲一个存储单元,通过(rear + 1) % capacity == front判断。此时rear指针的下一个位置是front,说明空间已满。

代码演示:

public class CircularQueue {//定义一个数组public int[] array;public int front;public int rear;//构造方法public CircularQueue(int k) {array = new int[k+1];}public boolean isFull() {return (rear + 1) % array.length == front;}//入队public boolean enQueue(int value) {//1.判满if (isFull()) {return false;}array[rear] = value;rear = (rear + 1) % array.length;return true;}//判空public boolean isEmpty() {return rear == front;}public boolean deQueue() {//判空if (isEmpty()) {return false;}front = (front + 1) % array.length;return true;}public int Front() {if (isEmpty()) {return -1;}return array[front];}public int Rear() {if (isEmpty()) {return -1;}int index = -1;if(rear == 0) {index = array.length-1;}else {index = rear-1;}return array[index];//(rear - 1 + capacity) % capacity}
}

双端队列的介绍和几个例题就留下次讲啦~

http://www.dtcms.com/a/507075.html

相关文章:

  • 第四章 串、数组和广义表——课后习题解练【数据结构(c语言版 第2版)】
  • 从C语言标准揭秘C指针:第 10 章:指针与动态内存:堆区内存的生命周期管理
  • 设计汽车网站外贸建站服务器怎么选
  • 微网站制作超链接太原网站开发工程师
  • 服装生产管理系统|基于SpringBoot和Vue的服装生产管理系统(源码+数据库+文档)
  • 牛客101:链表
  • 量化策略中三周期共振策略的仓位管理方法
  • 【python】快速实现pdf批量去除指定位置水印
  • 在 macOS 上用 Docker 为 Java 后端 常见开发需求搭建完整服务(详尽教程)
  • 网站建设翻译网站添加二维码
  • Debug —— Docker配置镜像后下载Mysql等报连接超时
  • 中冶交通建设集团网站发网站视频做啥格式最好
  • 软件定制一条龙整站多关键词优化
  • 【Vscode】显示多个文件 打开多个文件时实现标签栏多行显示
  • vue 技巧与易错
  • vscode编写Markdown文档
  • 使用VScode 插件,连接MySQL,可视化操作数据库
  • 基于微信小程序的公益捐赠安全平台9hp4t247 包含完整开发套件(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
  • 【论文精读】FlowVid:驯服不完美的光流,实现一致的视频到视频合成
  • 【C++】滑动窗口算法习题
  • C语言趣味小游戏----扫雷游戏
  • 三款AI平台部署实战体验:Dify、扣子与BuildingAI深度对比
  • 网站制作难不难小红书搜索优化
  • Python如何使用NumPy对图像进行处理
  • 房产中介网站开发站长工具之家
  • Linux服务器编程实践60-双向管道:socketpair函数的实现与应用场景
  • c++结构体讲解
  • 青岛商城网站建设网站相互推广怎么做
  • Linux学习笔记(九)--Linux进程终止与进程等待
  • 虚幻引擎5 GAS开发俯视角RPG游戏 P06-09 玩家等级与战斗接口