数据结构与算法之栈的实现及逆波兰计算器简易版

  1. 栈的介绍
    (1) 栈的英文为(stack)
    (2) 栈是一个先入后出(FILO-First In Last Out)的有序列表。
    (3) 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
    (4) 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
    (5) 图解方式说明出栈(pop)和入栈(push)的概念
  2. 栈的应用场景
    (1) 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
    (2) 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
    (3) 表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)。
    (4) 二叉树的遍历。
    (5) 图形的深度优先(depth 一 first)搜索法。
  3. 数组模拟栈
    (1)思路

    (2)代码实现
package com.datastrucate.stack;import java.util.Scanner;/*** ClassName:ArrayStackDemo* Package:com.datastrucate.stack* Description:** @Date:2021/5/11 16:18* @Author:hm*/public class ArrayStackDemo {public static void main(String[] args) { //测试一下 ArrayStack 是否正确// 先创建一个 ArrayStack 对象->表示栈ArrayStack stack = new ArrayStack(4);String key = "";boolean loop = true; //控制是否退出菜单Scanner scanner = new Scanner(System.in);while(loop) {System.out.println("show: 表示显示栈");System.out.println("exit: 退出程序");System.out.println("push:  表示添加数据到栈(入栈)");System.out.println("pop: 表示从栈取出数据(出栈)");System.out.println("请输入你的选择");key = scanner.next(); switch (key) {case "show":stack.list();break;case "push":System.out.println("请输入一个数");int value = scanner.nextInt();stack.push(value);break;case "pop":try {int res = stack.pop();System.out.printf("出栈的数据是 %d\n", res);} catch (Exception e) {//   TODO: handle exceptionSystem.out.println(e.getMessage());}break;case "exit":scanner.close();loop = false; break;default:break;}}System.out.println("程序退出~~~");}}//定义一个 ArrayStack 表示栈
class ArrayStack {private int maxSize; // 栈的大小private int[] stack; // 数组,数组模拟栈,数据就放在该数组private int top = -1;// top 表示栈顶,初始化为-1//构造器public ArrayStack(int maxSize) {this.maxSize = maxSize;stack = new int[this.maxSize];}//栈满public boolean isFull() {return top == maxSize - 1;}//栈空public boolean isEmpty() {return top == -1;}//入栈-pushpublic void push(int value) {//先判断栈是否满if(isFull()) {System.out.println("栈满");return;}top++;stack[top] = value;}//出栈-pop, 将栈顶的数据返回public int pop() {//先判断栈是否空if(isEmpty()) {//抛出异常throw new RuntimeException("栈空,没有数据~");}int value = stack[top];top--;return value;}//显示栈的情况[遍历栈], 遍历时,需要从栈顶开始显示数据public void list() {if(isEmpty()) {System.out.println("栈空,没有数据~~"); return;}//需要从栈顶开始显示数据for(int i = top; i >= 0 ; i--) {System.out.printf("stack[%d]=%d\n", i, stack[i]);}}}
  1. 栈实现综合计算器(中缀表达式)
    (1)问题描述
    使用栈来实现综合计算器

    (2)思路

    (3)代码实现
    先实现一位数的运算,在扩展到多位数的运算
package com.datastrucate.stack;import java.util.Stack;/*** ClassName:Calculator* Package:com.datastrucate.stack* Description:** @Date:2021/5/11 21:49* @Author:hm*/
public class Calculator {public static void main(String[] args) {//根据前面老师思路,完成表达式的运算String expression = "12+2*3-11"; // 7//如何处理多位数的问题?//String expression = "5+2*3-3";//8//创建两个栈,数栈,一个符号栈Stack<Integer> numStack = new Stack<Integer>();Stack<Character> operStack = new Stack<Character>();int index = 0;//记录运算表达式的下标,用于判断是否入栈结束int num1 = 0;//第一个操作数int num2 = 0;//第二个操作数int oper = 0;//操作符int res = 0;//运算结果char ch = ' ';//保存每次扫描的字符内容String  keepNum = "";//用于拼接多位数//循环express表达式while(true){ch = expression.substring(index,index+1).charAt(0);//判断ch的内容if(isOper(ch)){//ch是操作符//判断操作符栈是否为空if(!operStack.empty()){//不为空//如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符就需要从数栈中 pop 出两个数,//在从符号栈中 pop 出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈if (hasPriority(ch) <= hasPriority(operStack.peek())){num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = calculate(num1, num2, oper); //把运算的结果如数栈numStack.push(res); //然后将当前的操作符入符号栈operStack.push(ch);}else{//优先级大于栈内的则入栈operStack.push(ch);}}else{//操作栈为空,入栈operStack.push(ch);}}else{//为数字//1. 当处理多位数时,不能发现是一个数就立即入栈,因为他可能是多位数// 2. 在处理数,需要向 expression 的表达式的 index 后再看一位,如果是数就进行扫描,如果是符号才入栈//3. 因此我们需要定义一个变量 字符串,用于拼接keepNum += ch;  // 处理多位数//如果 ch 已经是 expression 的最后一位,就直接入栈if (index == expression.length()-1) {numStack.push(Integer.parseInt(keepNum));}else{//判断下一个字符是不是数字,如果是数字,就继续扫描,如果是运算符,则入栈// 注意是看后一位,不是index++;if (isOper(expression.substring(index+1,index+2).charAt(0))) { //如果后一位是运算符,则入栈 keepNum = "1" 或者 "123"numStack.push(Integer.parseInt(keepNum));//注意keepNum 清空keepNum = "";}}}index++;//下标后移,并判断是否到结尾if (index >= expression.length()){break;//结束循环}}//当表达式扫描完毕,就顺序的从 数栈和符号栈中 pop 出相应的数和符号,并运行while(true){//如果符号栈为空,则计算到最后的结果, 数栈中只有一个数字【结果】if(operStack.isEmpty()) {break;}num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = calculate(num1, num2, oper);numStack.push(res);//入栈}//将数栈的最后数,pop 出,就是结果int result = numStack.pop();System.out.printf("表达式 %s = %d", expression, result);}//计算private static int calculate(int num1, int num2, int oper) {int res = 0; // res 用于存放计算的结果switch (oper) {case '+':res = num1 + num2;break;case '-':res = num2 - num1;// 注意顺序break;case '*':res = num1 * num2;break;case '/':res = num2 / num1;break;default:break;}return res;}//判断操作符优先级private static int hasPriority(int oper) {//数字越大,则优先级就越高. public int priority(int oper) {if(oper == '*' || oper == '/'){return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1; //  假定目前的表达式只有 +, - , * , /}}//判断字符是否为操作符private static boolean isOper(char ch) {return ch == '+' | ch == '-'| ch=='*' | ch == '/';}}
  1. 逆波兰计算器的具体实现(中缀转后缀)
    我们完成一个逆波兰计算器,要求完成如下任务:
    输入一个逆波兰表达式(后缀表达式),使用栈(Stack), 计算其结果

    (1)大体思路
    第一步:将中缀表达式转存为List数组,方便遍历,不需要声明下标变量
    第二步:将中缀表达式list数组变成后缀表达式list数组
    第三步:后缀表达式实现进行计算实现逆波兰计算器
    (2)具体实现思路
    第一步实现:
    ① 循环中缀表达式的每一个字符,判断是操作数还是操作符
    ② 如果是操作符,则加入到list数组中,指针后移
    ③ 如果是数字,需要考虑多位数,则循环拼接数字,放入list数组
    第二步实现:
    (1)初始化两个栈:运算符栈 s1 和储存中间结果的栈 s2;
    (2)从左至右扫描中缀表达式;
    (3)遇到操作数时,将其压 s2;
    (4)遇到运算符时,比较其与 s1 栈顶运算符的优先级:
    ① 如果 s1 为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    ② 否则,若优先级比栈顶运算符的高,也将运算符压入 s1;
    ③ 否则,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到(4-1)与 s1 中新的栈顶运算符相比较;
    (5)遇到括号时:
    ① 如果是左括号“(”,则直接压入 s1
    ② 如果是右括号“)”,则依次弹出 s1 栈顶的运算符,并压入 s2,直到遇到左括号为止,此时将这一对括号丢弃
    (6)重复步骤 2 至 5,直到表达式的最右边
    (7) 将 s1 中剩余的运算符依次弹出并压入 s2
    (8) 依次弹出 s2 中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
    第三步:遍历后缀表达式list数组,若为数字则入栈,若为操作符,则pop出两个数进行计算
    (3)代码实现
package com.datastrucate.stack;import java.util.ArrayList;
import java.util.List;
import java.util.Stack;/*** ClassName:PolandNotation 逆波兰计算器(中缀转后缀)* Package:com.datastrucate.stack* Description:** @Date:2021/5/12 15:50* @Author:hm*/public class PolandNotation {public static void main(String[] args) {//完成将一个中缀表达式转成后缀表达式的功能//说明//1. 1+((2+3)×4)-5 => 转成  1 2 3 + 4 × + 5 –//2. 因为直接对str 进行操作,不方便,因此 先将  "1+((2+3)×4)-5" =》 中缀的表达式对应的List//   即 "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]//3. 将得到的中缀表达式对应的List => 后缀表达式对应的List//   即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =》 ArrayList [1,2,3,+,4,*,+,5,–]String expression = "1+((2+3)*4)-5";//注意表达式List<String> infixExpressionList = toInfixExpressionList(expression);System.out.println("中缀表达式对应的List=" + infixExpressionList); // ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);System.out.println("后缀表达式对应的List" + suffixExpreesionList); //ArrayList [1,2,3,+,4,*,+,5,–]System.out.printf("expression=%d", calculate(suffixExpreesionList)); // ?}//第一步:将 中缀表达式转成对应的List//  s="1+((2+3)×4)-5";public static List<String> toInfixExpressionList(String s) {//定义一个List,存放中缀表达式 对应的内容List<String> ls = new ArrayList<String>();int i = 0; //这时是一个指针,用于遍历 中缀表达式字符串String str; // 对多位数的拼接char c; // 每遍历到一个字符,就放入到cdo {//如果c是一个非数字,我需要加入到lsif((c=s.charAt(i)) < 48 ||  (c=s.charAt(i)) > 57) {ls.add("" + c);i++; //i需要后移} else { //如果是一个数,需要考虑多位数str = ""; //先将str 置成"" '0'[48]->'9'[57]while(i < s.length() && (c=s.charAt(i)) >= 48 && (c=s.charAt(i)) <= 57) {str += c;//拼接i++;}ls.add(str);}}while(i < s.length());return ls;//返回}//即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =》 ArrayList [1,2,3,+,4,*,+,5,–]//第二步:将得到的中缀表达式对应的List => 后缀表达式对应的Listpublic static List<String> parseSuffixExpreesionList(List<String> ls) {//定义两个栈Stack<String> s1 = new Stack<String>(); // 符号栈//说明:因为s2 这个栈,在整个转换过程中,没有pop操作,而且后面我们还需要逆序输出//因此比较麻烦,这里我们就不用 Stack<String> 直接使用 List<String> s2//Stack<String> s2 = new Stack<String>(); // 储存中间结果的栈s2List<String> s2 = new ArrayList<String>(); // 储存中间结果的Lists2//遍历lsfor(String item: ls) {//如果是一个数,加入s2if(item.matches("\\d+")) {s2.add(item);} else if (item.equals("(")) {s1.push(item);} else if (item.equals(")")) {//如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃while(!s1.peek().equals("(")) {s2.add(s1.pop());}s1.pop();//!!! 将 ( 弹出 s1栈, 消除小括号} else {//当item的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较//问题:我们缺少一个比较优先级高低的方法while(s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item) ) {s2.add(s1.pop());}//还需要将item压入栈s1.push(item);}}//将s1中剩余的运算符依次弹出并加入s2while(s1.size() != 0) {s2.add(s1.pop());}return s2; //注意因为是存放到List, 因此按顺序输出就是对应的后缀表达式对应的List}//第三步:完成对逆波兰表达式的运算public static int calculate(List<String> ls) {// 创建给栈, 只需要一个栈即可Stack<String> stack = new Stack<String>();// 遍历 lsfor (String item : ls) {// 这里使用正则表达式来取出数if (item.matches("\\d+")) { // 匹配的是多位数// 入栈stack.push(item);} else {// pop出两个数,并运算, 再入栈int num2 = Integer.parseInt(stack.pop());int num1 = Integer.parseInt(stack.pop());int res = 0;if (item.equals("+")) {res = num1 + num2;} else if (item.equals("-")) {res = num1 - num2;} else if (item.equals("*")) {res = num1 * num2;} else if (item.equals("/")) {res = num1 / num2;} else {throw new RuntimeException("运算符有误");}//把res 入栈stack.push("" + res);}}//最后留在stack中的数据是运算结果return Integer.parseInt(stack.pop());}}//编写一个类 Operation 可以返回一个运算符 对应的优先级
class Operation {private static int ADD = 1;private static int SUB = 1;private static int MUL = 2;private static int DIV = 2;//写一个方法,返回对应的优先级数字public static int getValue(String operation) {int result = 0;switch (operation) {case "+":result = ADD;break;case "-":result = SUB;break;case "*":result = MUL;break;case "/":result = DIV;break;default:System.out.println("不存在该运算符" + operation);break;}return result;}}

数据结构与算法之栈的实现及逆波兰计算器简易版相关推荐

  1. 数组结构与算法-036-042 前中后缀表达式-逆波兰计算器

    036 前缀 中缀 后缀(逆波兰表达式)表达式 前缀表达式 前缀表达式(波兰表达式) 前缀表达式又称波兰表达式,前缀表达式的运算符位于操作数之前 举例说明:(3 + 4) * 5 -6 对应的前缀表达 ...

  2. 数据结构与算法之栈入门题目

    数据结构与算法之栈题目 目录 用数组实现大小固定的队列和栈 实现一个特殊的栈,在实现栈的基础功能上,再实现返回栈中最小元素的操作 如果仅用栈结构实现队列结构和如何仅用队列结构实现栈结构 1. 用数组实 ...

  3. 数据结构与算法--利用栈实现队列

    利用栈实现队列 上一节中说明了栈的特点 后进先出,我们用数组的方式实现了栈的基本操作api,因此我们对栈的操作是不考虑排序的,每个api的操作基本都是O(1)的世界,因为不考虑顺序,所以找最大,最小值 ...

  4. 数据结构与算法--简单栈实现及其应用

    栈 栈(Stack)是一种限制插入和删除只能在一个位置上进行的表,改位置是表的末端,叫做栈顶top.栈的基本操作有push (进栈)pop(出栈) 栈又叫做LIFO(后进先出)表,下图展示普通push ...

  5. C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划

    C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划 博文末尾支持二维码赞赏哦 _ github 章3 Stack栈 和 队列Queue= ...

  6. 新星计划Day7【数据结构与算法】 栈Part1

    新星计划Day7[数据结构与算法] 栈Part1

  7. c语言将AOE网络的数据写入TXT文档中,数据结构与算法学习辅导及习题详解.张乃孝版-C/C++文档类资源...

    数据结构与算法学习辅导及习题详解.张乃孝版.04年10月 经过几年的努力,我深深体会到,编写这种辅导书要比编写一本湝通教材困难得多. 但愿我的上述理想,在本书中能够得以体现. 本书的组织 本书继承了& ...

  8. 数据结构:栈实现逆波兰计算器

    栈实现逆波兰计算器 前言 上篇博文中已经介绍了栈实现中缀表达式计算器,中缀表达式形如 "1+((2+3)*4)-5" 对人比较容易计算,但对于计算机却是一件比较困难的事,而后缀表达 ...

  9. 栈结构应用_普通计算器和逆波兰计算器

    栈的运用--普通计算器和逆波兰计算器 用栈实现计算器,这个比较难.有兴趣和热情的朋友,你可以看看.没有的,建议你看下一个数据结构. 逆波兰计算器是我们的终极目标,在实现目标之前,需要不断积累,所以我们 ...

  10. java stack 从1.5开始?_java数据结构与算法之栈(Stack)设计与实现

    本篇是java数据结构与算法的第4篇,从本篇开始我们将来了解栈的设计与实现,以下是本篇的相关知识点: 栈的抽象数据类型 栈是一种用于存储数据的简单数据结构,有点类似链表或者顺序表(统称线性表),栈与线 ...

最新文章

  1. 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续1)
  2. WebService using Spring throwed org.xml.sax.SAXException: Bad envelope tag: htm
  3. RHEL7 下双网卡绑定做主备(冗余)
  4. 互联网1分钟 | 1009
  5. mysql 取左_MySQL select语句从字符串左侧获取5个字符
  6. oss多线程 上传_oss-android/ios-sdk 断点续传(多线程)
  7. 【kafka】kafka 消费速度 小于 日志清理速度 (kafka数据被清理了)会发生什么 auto.offset.reset 参数
  8. 计算机课外作业,东南大学微机课外作业
  9. 算法学习_简单递归算法
  10. 著者四角号码查询_古籍检索史料检索.ppt
  11. Linux环境变量PSI指什么,psi是什么单位,pSI指标应用原则
  12. 重装电脑?先来个PE盘!
  13. 个人的工作总结(和工作规划)
  14. 目标检测:传统目标检测方法
  15. linux打开python3_号外:RIDE 可以在 linux+python3 的环境中运行啦!
  16. 国债期货matlab,Matlab和国债期货的那些事儿~(四)——关键利率法在利率风险管理中的运用...
  17. MATLAB基础—算数运算符
  18. 点击按钮返回数组 ages 中所有元素都大于输入框指定数值的元素和 $set()
  19. hbase集群 数据写入_一种构建HBase集群全文索引方法,数据读取方法以及数据写入方法与流程...
  20. 谷歌chrome浏览器扩展Fatkun图片批量下载

热门文章

  1. 小学计算机专业说课稿模板,小学信息技术计算机的小管家说课稿
  2. WPF学习记录1:ListView的一个模板
  3. 计算机审计中级题库,中级审计师用什么题库练习呢
  4. dxgi的概念以及奇怪问题处理
  5. 用计算机怎么管理小米路由器,小米路由器电脑怎么设置_小米路由器怎么用电脑设置?-192路由网...
  6. vue实现登录注册模板
  7. imageAI基本使用
  8. 人工智能数学基础——贝叶斯分析
  9. python字典的key提取_python 字典操作提取key,value
  10. 支持javascript的ppt软件_14款基于Javascript的数据可视化工具