文章目录

  • 1.栈实现计算器(中缀表达式)
    • 1.1流程图
    • 1.2 代码实现
  • 2. 逆波兰(后缀)表达式实现
    • 2.1 初步实现
    • 2.2 中缀表达式转后缀表达式
      • 2.2.1步骤
      • 2.2.2 代码实现

1.栈实现计算器(中缀表达式)

1.1流程图

1.2 代码实现

public class Calculator {public static void main(String[] args) {String expression = "700*2*2-5+1-5+3-4";//创建数栈和运算符栈ArrayStackCal numStack = new ArrayStackCal(10);ArrayStackCal operStack = new ArrayStackCal(10);int index = 0;//用于扫描int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' '; //将扫描结果保存到chString keepNum = "";//用于拼接字符串while (true){//遍历表达式将字符保存到chch = expression.substring(index,index+1).charAt(0);//判断是否为运算符if (operStack.isOper(ch)) {if (!operStack.isEmpty()){if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {//运算优先级小于栈顶时计算num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = operStack.cal(num1, num2, oper);//将运算结果入数栈numStack.push(res);//将当前操作符入符号栈operStack.push(ch);} else  {//运算优先级大于栈顶时入符号栈operStack.push(ch);}}else {//如果为空直接入栈operStack.push(ch);}}else {//如果下一位还是数字就拼接keepNum += ch;//如果ch已经是expression的最后一位,就直接入栈if (index == expression.length() - 1) {numStack.push(Integer.parseInt(keepNum));}else{//判断下一个字符是不是数字,如果是数字,就继续扫描,如果是运算符,则入栈//注意是看后一位,不是index++if (operStack.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 = operStack.cal(num1,num2,oper);numStack.push(res);}int res2 = numStack.pop();System.out.println("表达式"+expression+"="+res2);}
}//继承ArrayStack用数组实现栈
class ArrayStackCal extends ArrayStack{public ArrayStackCal() {}public ArrayStackCal(int maxSize) {super(maxSize);}/*** 返回运算符的优先级,用数字表示* @param oper* @return*/public int priority(int oper){if (oper=='*'||oper=='/'){return 1;}else if (oper=='+' || oper=='-'){return 0;}else {return -1;}}/*** 判断是否是一个运算符* @param val* @return*/public boolean isOper(char val){return val =='+' ||val =='-' || val =='*'|| val =='/';}/*** 返回计算结果* @param num1* @param num2* @param oper* @return*/public int cal(int num1,int num2,int oper){int res = 0;//计算结果switch (oper){case '+':res = num2 + num1;break;case '-':res = num2 - num1;break;case '*':res = num2 * num1;break;case '/':res = num2 / num1;break;default:break;}return res;}}

ArrayStack

class ArrayStack implements Stack1{public int maxSize;//栈的最大长度public int[] stack;public int top = -1;//栈顶public ArrayStack() {}public ArrayStack(int maxSize) {this.maxSize = maxSize;stack=new int[this.maxSize];}@Overridepublic int getSize() {return stack.length;}@Overridepublic boolean isEmpty() {return top==-1;}@Overridepublic void push(int value) {if (isFull()){System.out.println("栈满!");return;}top++;stack[top]=value;}public boolean isFull(){return top==maxSize-1;}@Overridepublic int pop() {if (isEmpty()){throw  new RuntimeException("栈空,无法取出数据!");}int value = stack[top];top--;return value;}@Overridepublic int peek() {//返回栈顶的值return stack[top];}public void traverse(){if (isEmpty()){System.out.println("栈空,无法取出数据!");return;}for (int i = top; i >=0 ; i--) {System.out.println("stack["+i+"]"+"="+stack[i]);}}
}

stack1

public interface Stack1 {int getSize();boolean isEmpty();void push(int e);int pop();int peek();
}

2. 逆波兰(后缀)表达式实现

例如:(3+4)X5-6对应的后缀表达式就是,针对后缀表达式求值步骤如下:
1.从左至右扫描,将3和4压入堆栈;
2.遇到+运算符,因此弹出4和3 (4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
3.将5入栈;
4.接下来是X运算符,因此弹出5和7,计算出7X5=35,将35入栈;
5.将6入栈;
6.最后是-运算符,计算出35-6的值,即29,由此得出最终结果

2.1 初步实现

实现思路

  1. 定义表达式

  2. 将表达式按空格分割放入列表

  3. 计算结果 :从左到右扫描,扫到的是数字就入栈,符号就pop出两个数字然后进行运算,再将结果入栈循环执行。直到最后还在栈中的元素就是结果。

  4. 返回结果

//逆波兰表达式的计算
public class PolanNotation {public static void main(String[] args) {//定义逆波兰表达式String expression = "3 4 + 5 * 6 -";ArrayList<String> list = getListString(expression);System.out.println(list);int cal = cal(list);System.out.println(cal);}/*** 将表达式放入ArrayList中* @param expression* @return*/public static ArrayList<String> getListString(String expression){//将表达式按空格分割String[] s = expression.split(" ");ArrayList<String> list = new ArrayList<>();//将表达式放入ArrayList中for (String s1 : s) {list.add(s1);}return list;}public static int cal(ArrayList<String> list){Stack<String> stack = new Stack<>();int num1 = 0;int num2 = 0;int res = 0;//存放运算结果for (String s : list) {//用正则表达式取出数if(s.matches("\\d+")){//匹配的是多位数stack.push(s);}else {num1 = Integer.parseInt(stack.pop());num2 = Integer.parseInt(stack.pop());switch (s){case "+":res = num2+num1;break;case "-":res = num2-num1;break;case "*":res = num2*num1;break;case "/":res = num2/num1;break;default:throw new RuntimeException("运算符有误");}//将计算结果入栈stack.push(""+res);}}//返回栈中最后剩下的元素return Integer.parseInt(stack.pop());}
}


这里表达式是后缀表达式,下面添加中缀转后缀表达式的实现。

2.2 中缀表达式转后缀表达式

2.2.1步骤

1)初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2)从左至右扫描中缀表达式; .
3)遇到操作数时,将其压s2;
4)遇到运算符时,比较其与s1栈顶运算符的优先级:
1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
5)遇到括号时:
(1) 如果是左括号“(”,则直接压入s1
(2)如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6)重复步骤2至5,直到表达式的最右边
7)将s1中剩余的运算符依次弹出并压入s2
8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

举例 1+((2+3)X4)-5

扫描到的元素 s2 (栈底->栈顶) s1(栈底->栈顶) 说明
1 1 数字,入栈s2
+ 1 + s1为空,入栈s1
( 1 + ( 左括号,入栈s1
( 1 + ( ( 左括号,入栈s1
2 1 2 + ( ( 数字,入栈s2
+ 1 2 + ( ( + s1栈顶为左括号 ,入栈s1
3 1 2 3 + ( ( + 数字,入栈s2
) 1 2 3 + + ( 右括号,弹出运算符直到遇到左括号
* 1 2 3 + + ( * s1栈顶为左括号,入栈s1
4 1 2 3 + 4 + ( * 数字,入栈s2
) 1 2 3 + 4 * + 右括号,弹出运算符直到遇到左括号
- 1 2 3 + 4 * + - -与+优先级相同,弹出+,压入-
5 1 2 3 + 4 * + 5 - 数字,入栈s2
扫描结束 1 2 3 + 4 * + 5 - s1剩余运算符压入s2

2.2.2 代码实现

//逆波兰表达式的计算
public class PolanNotation {public static void main(String[] args) {String expression2 = "1+((2+3)*4)-5";//将中缀表达式放入集合List<String> list1 = toInfixExpressionList(expression2);System.out.println("转换前"+list1);//将中缀表达式转为后缀表达式List<String> list2 = parseSuffixExpreesionList(list1);System.out.println("转换后"+list2);int res = cal(list2);System.out.println(expression2+"="+res);
//        //定义逆波兰表达式
//        String expression = "3 4 + 5 * 6 -";
//        ArrayList<String> list = getListString(expression);
//        System.out.println(list);
//        int cal = cal(list);
//        System.out.println(cal);}/*** 将中缀表达式转为后缀表达式* @param list* @return*/public static List<String> parseSuffixExpreesionList(List<String> list){Stack<String> s1 = new Stack<>();//存放运算符List<String> s2 = new ArrayList<>();//存放中间结果for (String s : list) {if (s.matches("\\d+")){//遇到操作数时,将其放入s2;s2.add(s);}else if(s.equals("(")) {//如果是左括号“(”,则直接压入s1s1.push(s);}else if(s.equals(")")){//)如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃while (!s1.peek().equals("(")) {s2.add(s1.pop());}s1.pop();//丢弃左括号}else {//如果是运算符,判断优先级while (s1.size()!=0 && Operation.getValue(s1.peek())>= Operation.getValue(s)){//若当前运算符优先级小于等于栈顶元素将s1栈顶的运算符弹出并放入到s2中,再次循环判断s2.add(s1.pop());}//其他情况, 如果s1为空,或栈顶运算符为左括号“(”,优先级比栈顶运算符的高,入栈s1.push(s);}}//将s1中剩余的运算符依次弹出放入s2while (s1.size() !=0){s2.add(s1.pop());}return s2;}/*** 将中缀表达式放入集合* @param s* @return*/public static List<String> toInfixExpressionList(String s){List<String> list = new ArrayList<>();String str;//拼接字符串char c  ;//存放遍历的字符int i=0; //用于遍历字符串do {if ((c=s.charAt(i))<48||(c=s.charAt(i))>57){//当c为运算符时list.add(""+c);i++;}else {//当c为一个数时str="";//将str置空while (i<s.length() && (c=s.charAt(i))>=48 &&(c=s.charAt(i))<=57){str+=c;i++;}list.add(str);}}while (i < s.length());return list;}/*** 将后缀表达式放入ArrayList中* @param expression* @return*/public static List<String> getListString(String expression){//将表达式按空格分割String[] s = expression.split(" ");List<String> list = new ArrayList<>();//将表达式放入ArrayList中for (String s1 : s) {list.add(s1);}return list;}public static int cal(List<String> list){Stack<String> stack = new Stack<>();int num1 = 0;int num2 = 0;int res = 0;//存放运算结果for (String s : list) {//用正则表达式取出数if(s.matches("\\d+")){//匹配的是多位数stack.push(s);}else {num1 = Integer.parseInt(stack.pop());num2 = Integer.parseInt(stack.pop());switch (s){case "+":res = num2+num1;break;case "-":res = num2-num1;break;case "*":res = num2*num1;break;case "/":res = num2/num1;break;default:throw new RuntimeException("运算符有误");}//将计算结果入栈stack.push(""+res);}}//返回栈中最后剩下的元素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:break;}return result;}}

(数据结构与算法)使用栈来实现综合计算器相关推荐

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

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

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

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

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

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

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

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

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

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

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

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

  7. 数据结构与算法(2)——栈和队列

    前言:题图无关,只是好看,接下来就来复习一下栈和队列的相关知识 前序文章: 数据结构与算法(1)--数组与链表(https://www.jianshu.com/p/7b93b3570875) 栈 什么 ...

  8. 【数据结构与算法】栈与队列

    栈 一.什么是栈? 1.后进者先出,先进者后出,这就是典型的"栈"结构. 2.从栈的操作特性来看,是一种"操作受限"的线性表,只允许在端插入和删除数据. 二.为 ...

  9. 数据结构与算法之-----栈的应用(三)

    [ 写在前面的话:本专栏的主要内容:数据结构与算法. 1.对于​​​​​​​初识数据结构的小伙伴们,鉴于后面的数据结构的构建会使用到专栏前面的内容,包括具体数据结构的应用,所使用到的数据结构,也是自己 ...

  10. 数据结构与算法之-----栈的应用(二)

    [ 写在前面的话:本专栏的主要内容:数据结构与算法. 1.对于​​​​​​​初识数据结构的小伙伴们,鉴于后面的数据结构的构建会使用到专栏前面的内容,包括具体数据结构的应用,所使用到的数据结构,也是自己 ...

最新文章

  1. jQuery对下拉框、单选框、多选框的处理
  2. IP分类以及特殊IP
  3. 消除软硬件鸿沟,芯客网完美支持智能硬件在移动互联时代的爆发
  4. MySQL5.5.27使用Restore From SQL Dump功能导入数据库表中出现Row size too large
  5. 利用深度学习技术自动可靠的叶病检测(附数据+分割分类详细+公共总结)
  6. linq的字段自增长属性设置_云途晨报9月9日前,这5类ebay物品属性必须完成更新;Wish体积重计算方式即将更新...
  7. python中run函数作用_python3多线程中如何改写run()函数?
  8. Java 多线程详解(三)------线程的同步
  9. 【统计学】10个必知必会的统计学问题 (附答案)
  10. sl跨域访问-学习笔记2
  11. Linux 上最好的视频编辑软件
  12. cmd net 命令
  13. 调查计算机游戏的目的有哪些,幼儿成长手册我参与的调查_计算机游戏对幼儿成长影响的调查分析...
  14. 字符串拼接用逗号隔开的四种方法
  15. wetool个人版_淘客干货:用了3年的wetool也没能幸免
  16. 官宣!CATCTF不日开赛!!
  17. php html注释多行,css多行注释怎么写
  18. 如何从一个大规模的文本中筛选出符合条件的记录
  19. (c语言详解)07-图6 旅游规划(详细解释)
  20. 【Python开发】Flask中的单点登录解决方案

热门文章

  1. C++ Primer 5th笔记(chap 17 标准库特殊设施)流随机访问
  2. 以太坊知识教程------智能合约(1)基本概念
  3. Linux常用的基本命令cp、mv、rm、cat、find(三)
  4. Django中Model继承的三种方式
  5. autossh端口映射
  6. 无线网络渗透测试-使用Aircrack-ng工具破解无线网络
  7. 隐藏基于对话框的MFC应用程序窗口的方法
  8. 设计模式C++实现(11)——装饰模式
  9. 135. 最大子序和【前缀和 单调队列】
  10. 1034 Head of a Gang (30 分) 【难度: 中 / 知识点: 并查集】