中缀表达式使用栈实现计算器
package stack;
//中缀表达式使用栈实现计算器
import java.util.Scanner;
//定义一个ArrayStack2表示栈
class ArrayStack2{
private int maxSize;//栈的大小
private int[] stack;//栈的数据存在该数组中
private int top=-1;//top表示栈顶,没有数据时为-1
private int num1;
private int num2;
private int oper;
//构造器
public ArrayStack2(int maxSize){
this.maxSize=maxSize;
stack=new int[this.maxSize];
}
//返回当前栈顶的值
public int peek(){
return stack[top];
}
//判断栈是否为满
public boolean isFull(){
return top==maxSize-1;
}
//判断栈是否为空
public boolean isEmpty(){
return top==-1;
}
//入栈
public void Push(int value){
//判断栈是否未满
if (isFull()){
System.out.println("栈满");
return;
}
top++;
stack[top]=value;
}
//出栈,将栈顶的数据返回
public int Pop(){
//判断栈是否空
if (isEmpty()){
//抛出异常
throw new RuntimeException("栈空");
//return;//不需要return,抛出异常本身就带有终止程序
}
int value=stack[top];
top--;
return value;
}
//显示栈的情况
public void disPlay(){
//遍历时需要从栈顶开始显示数据
if (isEmpty()){
System.out.println("栈空,没有数据");
return;
}
for (int i = top; i>=0 ; i--) {//从栈顶开始遍历
System.out.println("第"+i+"个数据为"+stack[top]+" ");
}
}
//返回运算符的优先级,优先级使用数字表示,数字越大优先级越高,假定表达式中只含有+-*/
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){
this.num1 = num1;
this.num2 = num2;
this.oper = oper;
int res=0;//用于存放计算结果
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;
}
}
public class Calculator {
public static void main(String[] args) {
//根据思路完成表达式的计算
Scanner sc=new Scanner(System.in);
System.out.println("请输入计算表达式:");
String expression=sc.next();
//创建两个栈,数栈和符号栈
ArrayStack2 numStack=new ArrayStack2(10);
ArrayStack2 operStack=new ArrayStack2(10);
//定义相关变量
int index=0;//用于扫描
int num1=0;
int num2=0;
int oper=0;
int res=0;
char ch=' ';//将每次扫描得到的char保存在ch中
//定义一个字符串变量用于拼接多位数
String keepNum="";
//开始用while循环扫描expression
while (true){
//依次得到expression的每一个字符
ch=expression.subSequence(index,index+1).charAt(0);
//判断ch是什么,按照相应的方式处理
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=numStack.cal(num1,num2,oper);
//把运算结果入数栈
numStack.Push(res);
//然后把当前符号入符号栈
operStack.Push(ch);
}else {//如果当前操作符大于栈中栈中的操作符优先级那就直接入栈
operStack.Push(ch);
}
}else{//如果为空
//直接入栈
operStack.Push(ch);
}
}else{//如果是数字,直接入数栈
//numStack.Push(ch-48);//从字符转换为数字
//分析多位数入栈情况
//1.当处理多位数时,不能发现是数字就入栈,因为可能是多位数
//2.在处理数时,需要向表达式的index再往后看一位来判断它是不是多位数,如果是就继续扫描,否则入栈
//3.需要定义一个字符串变量用于拼接
//处理多位数
keepNum+=ch;
//如果ch已经是表达式的最后一位就直接入栈
if (index==expression.length()-1){
numStack.Push(Integer.parseInt(keepNum));
}else{
//判断下一个字符是不是数字,是数字继续扫描,如果是运算符就入数栈
//只是向后再看一位不是index++
if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
//如果条件满足那么后一位就是运算符,那么就入数栈,keep="1","123"
numStack.Push(Integer.parseInt(keepNum));//要将keepNum转化为数字入数栈,此方法就可以
//入数栈后记得将keepNum清空,不然下一次会在原来基础上拼接
keepNum="";
}
}
}
//让index++,并判断是否扫描到最后
index++;
if (index>=expression.length()){
break;
}
}
//做扫描完毕后的处理
while (true){
//如果符号栈为空计算结束,数占中只有一个数值就是结果
if (operStack.isEmpty()){
break;
}
num1=numStack.Pop();
num2=numStack.Pop();
oper=operStack.Pop();
res=numStack.cal(num1,num2,oper);
numStack.Push(res);//入栈
}
int res2=numStack.Pop();
System.out.println("结果为:");
System.out.println(res2);
}
}
中缀表达式转后缀表达式计算器
package stack;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class PolandNotation {
public static void main(String[] args) {
//中缀表达式转后缀表达式:1+((2+3)*4)-5——》1 2 3 + 4 * + 5 -
//1.将中缀表达式转化成中缀表达式对应的list
//2.将中缀表达式对应的list转化成后缀表达式对应的list
// [1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]-》[1,2,3,+,4,*,+,5,-],消除括号
String expression="1+((2+3)*4)-5";
List<String> infixExpressionList=toInfixExpressionList(expression);
System.out.println("中缀表达式对应的list="+infixExpressionList);
List<String> suffixExpressionList = parseSuffixExpressionList(infixExpressionList);
System.out.println("后缀表达式对应的list="+suffixExpressionList);
System.out.println(expression+"="+calculate(suffixExpressionList));
//先定义一个逆波兰表达式
//(3+4)*5-6-->3 4+ 5 * 6 -
//String suffixExpression="3 4 + 5 * 6 - ";//后缀表达式
//思路:
//1.先将表达式放在ArrayList当中,便于快速扫描
//2.将ArrayList传递给一个方法,配合栈完成计算
/*List<String> list=getListString(suffixExpression);
System.out.println("rpnList: "+list);
int res=calculate(list);
System.out.println(res);*/
}
// [1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]-》[1,2,3,+,4,*,+,5,-],消除括号
//方法:
public static List<String> parseSuffixExpressionList(List<String> ls){
//定义两个栈
Stack<String> s1=new Stack<String>();//符号栈
//因为s2这个栈,在整转换过程中,没有pop操作,我们后面要逆序输出后缀表达式
//因此我们不用 Stack<String>,只接使用List<String> s2
//Stack<String> s2=new Stack<String>();//存储中间结果栈
List<String> s2=new ArrayList<String>();//用于存储中间结果的ArrayList s2
//遍历ls
for(String item:ls){
//如果是一个数就入加入到s2
if (item.matches("\\d+")){//使用正则表达式
s2.add(item);
}else if(item.equals("(")){
s1.push(item);
}else if (item.equals(")")){
//如果是“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时这一对括号将丢弃
while (!s1.peek().equals("(")){//peek()查看栈顶的内容,并不改变
s2.add(s1.pop());//把s1内容弹出加入到s2中,知道遇到)结束
}
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压入s2栈中
s1.push(item);
}
}
//将s1中剩余的运算符依次弹出并加入到s2中
while (s1.size()!=0){
s2.add(s1.pop());
}
return s2;//因为是存放到list中,因此按顺序输出就是后缀表达式对应的list
}
//将中缀表达式转成对应的list
public static List<String> toInfixExpressionList(String s){
//定义一个List存放中缀表达式对应的内容
List<String> ls=new ArrayList<String>();
int i=0;//用于扫描中缀表达式字符串
String str;//用于对多位数进行拼接
char c;//每遍历一个字符,就放入到c
do {
//如果c是非数字,那么加到ls中
if ((c=s.charAt(i))<48||(c=s.charAt(i))>57){
ls.add(""+c);
i++;//需要后移
}else{//如果是数字,需要考虑多位数的问题
str="";//先将str置成空串
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=new ArrayList<String>();
for(String ele:split ){
list.add(ele);
}
return list;
}*/
//完成对逆波兰表达式的计算
/*
* 1.从左向右扫描,将3和4压入堆栈
* 2.遇到+运算符,弹出4和3(4是栈顶元素,3是次栈顶元素),计算3+4,将结果7入栈
* 3.将5入栈
* 4.接下来扫描到*运算符,弹出5和7,计算5*7,将结果34入栈
* 5.将6入栈
* 6.扫描到-运算符弹出6和35,计算35-6,将结果29入栈,得到最终结果
* */
public static int calculate(List<String> ls){
//创建一个栈即可
Stack<String> stack=new Stack<String>();
//遍历ls
for (String item:ls){
//使用正则表达式取出数
if (item.matches("\\d+")){//匹配的是多位数
//入栈
stack.push(item);
}else{
//弹出两个数并运算,再入栈
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());
}
}
//编一个比较运算符优先级的类
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("不存在该运算符!");
break;
}
return result;
}
}