1、栈的一个实际需求

请输入一个表达式:7x2x2-5+1-5+3-3

2、栈的介绍

  • 栈的英文为stack

  • 栈是一个**先入后出(FILO-First In Last Out) **的有序列表

  • 栈(stack) 是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。

  • 允许插入和删除的一端,为变化的一端,称为栈顶(Top) ,另一端为固定的一端,称为栈底(Bottom)

  • 根据栈的定义可知 ,最先放入栈中元素在栈底 ,最后放入的元素在栈顶

  • 删除元素刚好相反 ,最后放入的元素最先删除,最先放入的元素最后删除

  • 图解方式说明出栈(pop) 和入栈(push) 的概念

3、栈的应用场景

  • 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以
    回到原来的程序中。
  • 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆
    栈中。
  • 表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)
  • 二叉树的遍历
  • 图形的深度优先(depth 一 first)搜索法

4、栈的快速入门

  • 用数组模拟栈的使用,由于栈是一种有序列表,当然可以使用数组的结构来储存栈的数据内容,
    下面我们就用数组模拟栈的出栈,入栈等操作

  • 实现思路分析,并画出示意图

  • 代码实现

    import java.util.Scanner;public class ArrayStackDemo {public static void main(String[] args) {//测试一下 ArrayStack 是否正确//先创建一个 ArrayStack 对象->表示栈ArrayStack stack = newArrayStack(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//构造器publicArrayStack(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]);}}
    }    
  • 关于栈的一个小练习:使用链表来模拟【栈】

5、栈实现综合计算器(中缀表达式)

  • 使用栈来实现综合计算器

  • 思路分析(图解)

  • 代码实现【1. 先实现一位数的运算, 2. 扩展到多位数的运算】

    public class Calculator {public static void main(String[] args) {//根据前面老师思路,完成表达式的运算String expression = "7*2*2-5+1-5+3-4"; // 15//如何处理多位数的问题?//创建两个栈,数栈,一个符号栈ArrayStack2 numStack = newArrayStack2(10);ArrayStack2 operStack = newArrayStack2(10);//定义需要的相关变量int index = 0;//用于扫描int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' '; //将每次扫描得到 char 保存到 chString keepNum = ""; //用于拼接 多位数//开始 while 循环的扫描 expressionwhile(true) {//依次得到 expression 的每一个字符ch = expression.substring(index, index+1).charAt(0);//判断 ch 是什么,然后做相应的处理if(operStack.isOper(ch)) {//如果是运算符//判断当前的符号栈是否为空if(!operStack.isEmpty()) {//如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符//就需要从数栈中pop出两个数,//在从符号栈中pop出一个符号,进行运算,//将得到结果,入数栈,然后将当前的操作符入符号栈if(operStack.priority(ch) <= operStack.priority(operStack.peek()))                     {num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = numStack.cal(num1, num2, oper);//把运算的结果如数栈numStack.push(res);//然后将当前的操作符入符号栈operStack.push(ch);} else {//如果当前的操作符的优先级大于栈中的操作符, 就直接入符号栈.operStack.push(ch);}}else {//如果为空直接入符号栈..operStack.push(ch); // 1 + 3}} else { //如果是数,则直接入数栈//numStack.push(ch - 48); //? "1+3" '1' => 1//分析思路//1. 当处理多位数时,不能发现是一个数就立即入栈,因为他可能是多位数//2. 在处理数,需要向expression的表达式的index后再看一位//如果是数就进行扫描,如果是符号才入栈   //3. 因此我们需要定义一个变量字符串,用于拼接//处理多位数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 + 1, 并判断是否扫描到 expression 最后.index++;if (index >= expression.length()) {break;}}//当表达式扫描完毕,就顺序的从 数栈和符号栈中 pop 出相应的数和符号,并运行.while(true) {//如果符号栈为空,则计算到最后的结果, 数栈中只有一个数字【结果】if(operStack.isEmpty()) {break;}num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = numStack.cal(num1, num2, oper);numStack.push(res);//入栈}//将数栈的最后数,pop 出,就是结果int res2 = numStack.pop();System.out.printf("表达式 %s = %d", expression, res2);}
    }//先创建一个栈,直接使用前面创建好
    //定义一个 ArrayStack2 表示栈, 需要扩展功能
    class ArrayStack2 {private int maxSize; // 栈的大小private int[] stack; // 数组,数组模拟栈,数据就放在该数组private int top = -1;// top 表示栈顶,初始化为-1//构造器publicArrayStack2(int maxSize) {this.maxSize = maxSize;stack = new int[this.maxSize];}//增加一个方法,可以返回当前栈顶的值, 但是不是真正的 poppublic int peek() {return stack[top];}//栈满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]);}}//返回运算符的优先级,优先级是程序员来确定, 优先级使用数字表示//数字越大,则优先级就越高.public int priority(int oper) {if(oper == '*' || oper == '/'){return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1; // 假定目前的表达式只有 +, - , * , /}}//判断是不是一个运算符public boolean isOper(char val) {return val == '+' || val == '-' || val == '*' || val == '/';}//计算方法public int cal(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;}
    }
    

6、逆波兰计算器

​ 完成一个逆波兰计算器,要求完成如下任务:

  • 输入一个逆波兰表达式(后缀表达式),使用栈(Stack), 计算其结果

  • 支持小括号和多位数整数,这里对计算器进行简化,只支持对整数的计算

  • 思路分析

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

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Stack;
    public class PolandNotation {public static void main(String[] args) {//先定义给逆波兰表达式//(30+4)×5-6 => 30 4 + 5 × 6 - => 164// 4 * 5 - 8 + 60 + 8 / 2 => 4 5 * 8 - 60 + 8 2 / +//测试//说明为了方便,逆波兰表达式 的数字和符号使用空格隔开//String suffixExpression = "30 4 + 5 * 6 -";String suffixExpression = "4 5 * 8 - 60 + 8 2 / +"; // 76//思路//1. 先将 "3 4 + 5 × 6 - " => 放到 ArrayList 中//2. 将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈 完成计算List<String> list = getListString(suffixExpression);System.out.println("rpnList=" + list);int res = calculate(list);System.out.println("计算的结果是=" + res);}//将一个逆波兰表达式, 依次将数据和运算符 放入到 ArrayList 中public static List<String> getListString(String suffixExpression) {//将 suffixExpression 分割String[] split = suffixExpression.split(" ");List<String> list = newArrayList<String>();for(String ele: split) {list.add(ele);}return list;}//完成对逆波兰表达式的运算/** 1)从左至右扫描,将 3 和 4 压入堆栈;2)遇到+运算符,因此弹出4和3(4 为栈顶元素,3 为次顶元素),计算出 3+4 的值,得7,再将7入栈;3)将 5 入栈;4)接下来是×运算符,因此弹出 5 和 7,计算出 7×5=35,将 35 入栈;5)将 6 入栈;6)最后是-运算符,计算出 35-6 的值,即 29,由此得出最终结果*/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());}
    }
    

7、中缀表达式转换为后缀表达式

后缀表达式适合计算式进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将中缀表达式转成后缀表达式。

(1)具体实现步骤

  • 初始化两个栈:运算符栈 s1 和储存中间结果的栈 s2;

  • 从左至右扫描中缀表达式;

  • 遇到操作数时,将其压 s2;

  • 遇到运算符时,比较其与 s1 栈顶运算符的优先级:

    • 如果 s1 为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    • 否则,若优先级比栈顶运算符的高,也将运算符压入 s1;
    • 否则,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到(4-1)与 s1 中新的栈顶运算符相比较;
  • 遇到括号时:

    • 如果是左括号“(”,则直接压入 s1
    • 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
  • 重复步骤 2 至 5,直到表达式的最右边

  • 将 s1 中剩余的运算符依次弹出并压入 s2

  • 依次弹出 s2 中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

(2)举例说明

​ 将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下:

​ 因此结果为 :“1 2 3 + 4 × + 5 –”

(3)代码实现中缀表达式转为后缀表达式

  • 思路分析

  • 代码实现

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Stack;
    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)); // ?/*//先定义给逆波兰表达式//(30+4)×5-6 => 30 4 + 5 × 6 - => 164// 4 * 5 - 8 + 60 + 8 / 2 => 4 5 * 8 - 60 + 8 2 / +//测试//说明为了方便,逆波兰表达式 的数字和符号使用空格隔开//String suffixExpression = "30 4 + 5 * 6 -";String suffixExpression = "4 5 * 8 - 60 + 8 2 / +"; // 76//思路//1. 先将 "3 4 + 5 × 6 - " => 放到 ArrayList 中//2. 将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈 完成计算List<String> list = getListString(suffixExpression);System.out.println("rpnList=" + list);int res = calculate(list);System.out.println("计算的结果是=" + res);*/}//即 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 = newArrayList<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}//方法:将 中缀表达式转成对应的 List// s="1+((2+3)×4)-5";public static List<String> toInfixExpressionList(String s) {//定义一个 List,存放中缀表达式 对应的内容List<String> ls = newArrayList<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 中public static List<String> getListString(String suffixExpression) {//将 suffixExpression 分割String[] split = suffixExpression.split(" ");List<String> list = newArrayList<String>();for(String ele: split) {list.add(ele);}return list;}//完成对逆波兰表达式的运算/** 1)从左至右扫描,将 3 和 4 压入堆栈;2)遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;3)将 5 入栈;4)接下来是×运算符,因此弹出 5 和 7,计算出 7×5=35,将 35 入栈;5)将 6 入栈;6)最后是-运算符,计算出 35-6 的值,即 29,由此得出最终结果*/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 intADD = 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("不存在该运算符");break;}return result;}
    }
    

8、逆波兰计算器完整版

(1)完整版的逆波兰计算器功能

  • 支持 + - * / ( )

  • 多位数,支持小数

  • 兼容处理, 过滤任何空白字符,包括空格、制表符、换页符

【说明】逆波兰计算器完整版考虑的因素较多,仅供学习。其基本思路和前面一样,也是使用到:中缀表达式转后缀表达式

(2)代码实现

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
public class ReversePolishMultiCalc {/*** 匹配 + - * / ( ) 运算符*/static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)";static final String LEFT = "(";static final String RIGHT = ")";static final StringADD = "+";static final String MINUS= "-";static final String TIMES = "*";static final String DIVISION = "/";/*** 加減 + -*/static final int LEVEL_01 = 1;/*** 乘除 * /*/static final int LEVEL_02 = 2;/*** 括号*/static final int LEVEL_HIGH = Integer.MAX_VALUE;static Stack<String> stack = new Stack<>();static List<String> data = Collections.synchronizedList(new ArrayList<String>());/*** 去除所有空白符* @param s* @return*/public static String replaceAllBlank(String s ){// \\s+ 匹配任何空白字符,包括空格、制表符、换页符等等, 等价于[ \f\n\r\t\v]return s.replaceAll("\\s+","");}/*** 判断是不是数字 int double long float* @param s* @return*/public static boolean isNumber(String s){Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");return pattern.matcher(s).matches();}/*** 判断是不是运算符* @param s* @return*/public static boolean isSymbol(String s){return s.matches(SYMBOL);}/*** 匹配运算等级* @param s* @return*/public static int calcLevel(String s){if("+".equals(s) || "-".equals(s)){return LEVEL_01;} else if("*".equals(s) || "/".equals(s)){return LEVEL_02;}return LEVEL_HIGH;}/*** 匹配* @param s* @throws Exception*/public static List<String> doMatch (String s) throws Exception{if(s == null || "".equals(s.trim())) throw new RuntimeException("data is empty");if(!isNumber(s.charAt(0)+"")) throw new RuntimeException("data illeagle,start not with a number");s = replaceAllBlank(s);String each;int start = 0;for (int i = 0; i < s.length(); i++) {if(isSymbol(s.charAt(i)+"")){each = s.charAt(i)+"";//栈为空,(操作符,或者操作符优先级大于栈顶优先级 && 操作符优先级不是( )的优先级及是)不能直接入栈if(stack.isEmpty() || LEFT.equals(each)|| ((calcLevel(each) > calcLevel(stack.peek())) && calcLevel(each) < LEVEL_HIGH)){stack.push(each);}else if( !stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek()))                {//栈非空,操作符优先级小于等于栈顶优先级时出栈入列,直到栈为空,或者遇到了(,最后操作符入栈   while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())                        ){if(calcLevel(stack.peek()) == LEVEL_HIGH){break;}data.add(stack.pop());}stack.push(each);}else if(RIGHT.equals(each)){// ) 操作符,依次出栈入列直到空栈或者遇到了第一个)操作符,此时)出栈while (!stack.isEmpty() && LEVEL_HIGH >= calcLevel(stack.peek())){if(LEVEL_HIGH == calcLevel(stack.peek())){stack.pop();break;}data.add(stack.pop());}}start = i ; //前一个运算符的位置}else if( i == s.length()-1 || isSymbol(s.charAt(i+1)+"") ){each = start == 0 ? s.substring(start,i+1) : s.substring(start+1,i+1);if(isNumber(each)) {data.add(each);continue;}throw new RuntimeException("data not match number");}}//如果栈里还有元素,此时元素需要依次出栈入列,可以想象栈里剩下栈顶为/,栈底为+,//应该依次出栈入列,可以直接翻转整个 stack 添加到队列Collections.reverse(stack);data.addAll(newArrayList<>(stack));System.out.println(data);return data;}/*** 算出结果* @param list* @return*/public static Double doCalc(List<String> list){Double d = 0d;if(list == null || list.isEmpty()){return null;}if (list.size() == 1){System.out.println(list);d = Double.valueOf(list.get(0));return d;}ArrayList<String> list1 = newArrayList<>();for (int i = 0; i < list.size(); i++) {list1.add(list.get(i));if(isSymbol(list.get(i))){Double d1 = doTheMath(list.get(i - 2), list.get(i - 1), list.get(i));list1.remove(i);list1.remove(i-1);list1.set(i-2,d1+"");list1.addAll(list.subList(i+1,list.size()));break;}}doCalc(list1);return d;}/*** 运算* @param s1* @param s2* @param symbol* @return*/public static Double doTheMath(String s1,String s2,String symbol){Double result ;switch (symbol){caseADD : result = Double.valueOf(s1) + Double.valueOf(s2); break;case MINUS : result = Double.valueOf(s1) - Double.valueOf(s2); break;case TIMES : result = Double.valueOf(s1) * Double.valueOf(s2); break;case DIVISION : result = Double.valueOf(s1) / Double.valueOf(s2); break;default : result = null;}return result;}public static void main(String[] args) {//String math = "9+(3-1)*3+10/2";String math = "12.8 + (2 - 3.55)*4+10/5.0";try {doCalc(doMatch(math));} catch (Exception e) {e.printStackTrace();}}
}

数据结构与算法(3)栈相关推荐

  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. ib_logfile 在数据库中有何作用?
  2. Linux 下 PostgreSQL 源码编译安装
  3. java sftp nologin_SFTP连接通过Java询问奇怪的身份验证
  4. docker启动sqlserver_ASP.NET Core容器化技术Docker零基础从入门到实战演练
  5. [css] 使用css3画一个扇形
  6. TCP与UDP的选择--结合QQ来说明
  7. Redis缓存那点破事 , 绝杀面试官 25 问
  8. Protobuf c++使用小坑(set_allocated函数)
  9. Proxy error: Could not proxy request /api/ from localhost:8080 to http://localhost:80
  10. java 子目录_Java:子目录点
  11. 三分钟完全了解PyTorch中卷积层内部计算方法和权值初始值的来历,让你对模型有更深层次的理解
  12. java 一切object_javaObject类
  13. c# string 转 datetime_tesseract || PDF转PNG转txt
  14. [LintCode] Swap Nodes in Pairs
  15. 仿京东商城html网页源码
  16. Java读写文件的常用方法
  17. 形式语言与自动机理论期末复习
  18. 2018的趋势与展望(下)——记罗振宇“时间的朋友2017”跨年演讲
  19. 换了3根高清线后,第四根mini dp转HDMI线终于可以显示4K了
  20. 【系统分析师之路】第七章 复盘系统设计(业务流程建模)

热门文章

  1. JavaScript——本地存储 用户名存储案例
  2. Photoshop-颜色通道-原理(转)
  3. Android与H5交互探索之旅
  4. Isomap流行学习_机器学习
  5. IIC读写EEPROM
  6. 【C++】代码实现:全局钩子注入技术
  7. python数字位数重排_数位重排
  8. python易错题之作用域
  9. IIC总线及心率脉搏传感器
  10. 鼠标优化工具Mos Mac中文版