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

数据结构之栈和队列的应用

目录

一、栈的应用

1. 括号匹配

 2. 计算后缀表达式

方法一(栈)

方法二(数组模拟栈)

二、队列应用

1. 二叉树层序遍历

方法一(队列)

三、总结


一、栈的应用

1. 括号匹配

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。
class Solution {public boolean isValid(String s) {// 判断括号数是否匹配if (s.length() %2 == 1) {return false;}Stack<Character> S = new Stack();for (int i = 0; i < s.length(); ++i) {char ele = s.charAt(i);// 左括号if (containLeft(ele)) {S.push(ele);} else {if (S.empty()) {return false;}// 右括号if (CompareTo(S.peek(), ele)) {// 将栈顶元素弹出S.pop();} else {return false;}}}return S.empty() ? true : false;}// 包含左括号
public static boolean containLeft(char ch) {if (ch == '{') return true;if (ch == '(') return true;if (ch == '[') return true;return false;
}//  检验括号是否匹配public static boolean CompareTo(char forth, char latter) {if ((forth == '{' && latter == '}') || (forth == '(' && latter == ')') || (forth == '[' && latter == ']')) {return true;}return false;}
}   

 2. 计算后缀表达式

根据 逆波兰表示法,求该后缀表达式的计算结果。

有效的算符包括 +-*/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

  • 整数除法只保留整数部分。
  • 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

后缀表达式按照从左到右的运算规则,计算表达式需要一个栈存放操作数;假设表达式成立,依次获取每一个字符串,如果字符串是操作数,则直接入栈,如果字符串是操作符,出栈两次,首先出栈的是右操作数,后出栈的是左操作数,将运算得到的新操作数入栈。 

方法一(栈)

class Solution {public int evalRPN(String[] tokens) {Stack<Integer> S = new Stack<>();int i = 0;while (i < tokens.length) {String token = tokens[i++];if (isNumber(token)) {S.push(Integer.parseInt(token));} else {int num2 = S.pop();int num1 = S.pop();switch(token) {case "+":S.push(num1 + num2);break;case "-":S.push(num1 - num2);break;case "*":S.push(num1 * num2);break;case "/":S.push(num1 / num2);break;default:}}}return S.pop();}public boolean isNumber(String token) {return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));}
}

方法二(数组模拟栈)

class Solution {public int evalRPN(String[] tokens) {int n = tokens.length;int[] stack = new int[(n + 1) / 2];int index = -1;for (int i = 0; i < n; i++) {String token = tokens[i];switch(token) {case "+":index--;stack[index] += stack[index + 1];break;case "-":index--;stack[index] -= stack[index + 1];break;case "*":index--;stack[index] *= stack[index + 1];break;case "/":index--;stack[index] /= stack[index + 1];break;default:index++;stack[index] = Integer.parseInt(token);}}return stack[index];}
}

二、队列应用

1. 二叉树层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

 /** public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
public List<Integer> levelOrder(TreeNode node) {// 定义res存储结点的值List<Integer> res = new LinkedList<>();Queue<TreeNode> queue = new LinkedList<>();if (node != null) {queue.offer(node);}while (!queue.isEmpty()) {TreeNode ele = queue.poll();res.add(ele.val);// 判断结点是否有左右孩子if (ele.left != null) {queue.offer(ele.left);}if (ele.right != null) {queue.offer(ele.right);}}return res;
}

不同于题目的是,返回一个一维列表,但如果需要返回二维列表,我们不仅要实现层序遍历,还需要将同一层的结点放到一起。显然,上述的算法无法解决这个问题。


既然一个一个迭代无法满足要求,那么我们就可以考虑一层一层迭代。

我们定义一个队列,队列中存放同一层的结点。那么我们需要考虑如何迭代一层结点?

假设队列中存放了根节点root,此时队列的长度为1,那么我们迭代一次就可以让第一层所有结点出队。出队的同时,会将root的子节点存放到队列中。

此时队列的长度为2,我们迭代两次可以让第二层所有的结点出队,出队同时会让出队元素的子结点入队,且队列满足FIFO特点,因而可以保证从左至右遍历。

归纳总结可知,迭代的次数等于前一层的入队元素个数,因为出队同时要进队,因而前一层全部出队后,队列中的一定是当前层的元素,而且队列的长度一定等于当前层的结点个数,按照这个过程迭代,直至遍历完所有结点。

方法一(队列)

 /** public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList();if (root == null) {return res;}Queue<TreeNode> queue = new LinkedList<TreeNode>();queue.offer(root);while (! queue.isEmpty()) {List<Integer> level = new ArrayList<>();int currentLevelSize = queue.size();for (int i = 0; i < currentLevelSize; ++i) {TreeNode node = queue.poll();level.add(node);if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}res.add(level);}return res;}
}

三、总结

栈和队列的应用十分广泛,本文简单地展示了这两种数据结构的特点,然而它的魅力不止这些,相信读者一定会遇到更加有趣的算法。上述内容如果有错误的地方,希望大佬们可以指正。我一直在学习的路上,您的帮助使我收获更大!觉得对您有帮助的话,还请点赞支持!我也会不断更新文章!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【物联网技术大作业】设计一个智能家居的应用场景
  • 树莓派Pico开发板简介
  • 【网络】高级IO——阻塞IO和非阻塞IO的实现
  • 【项目一】基于pytest的自动化测试框架———解读requests模块
  • 【App】React Native
  • STM32的寄存器深度解析
  • 关系数据库,集合运算符,关系运算符
  • 1-4微信小程序基础
  • 苹果系统(MacOS)中的Finder如何方便展现根目录
  • 多线程篇(其它容器- CopyOnWriteArrayList)(持续更新迭代)
  • 嵌入式鸿蒙系统开发语言与开发方法分析
  • 什么是机器学习力场
  • 【H2O2|全栈】关于CSS(2)CSS基础(二)
  • 关于新版本 tidb dashboard API 调用说明
  • 推荐这款神器:Perplexity
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • canvas绘制圆角头像
  • Hibernate最全面试题
  • in typeof instanceof ===这些运算符有什么作用
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Mithril.js 入门介绍
  • SSH 免密登录
  • ------- 计算机网络基础
  • 力扣(LeetCode)357
  • 如何选择开源的机器学习框架?
  • 我与Jetbrains的这些年
  • 小李飞刀:SQL题目刷起来!
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • ​Java基础复习笔记 第16章:网络编程
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #if #elif #endif
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (35)远程识别(又称无人机识别)(二)
  • (C语言)球球大作战
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (MATLAB)第五章-矩阵运算
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (二)springcloud实战之config配置中心
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (转)德国人的记事本
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • ******之网络***——物理***
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .htaccess配置重写url引擎
  • .NET delegate 委托 、 Event 事件
  • .NET MAUI Sqlite程序应用-数据库配置(一)
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .net通过类组装数据转换为json并且传递给对方接口
  • .project文件
  • //解决validator验证插件多个name相同只验证第一的问题