用栈实现综合计算器(基础计算)

思路:在这里插入图片描述
插播小知识:
char表示字符,定义时使用用单引号表示,只能存储一个字符。
String表示字符串,定义时使用双引号表示,可以存储0个或多个字符,其实string类型就是char类型的数组表现形式。

substring的用法:官方的解释:The substring begins at the specified beginIndex and extends to the character at index endIndex - 1。直白的话:在beginindex开始,endindex-1结束,最后一个index不取。返回的是字符串中的部分字符串。
charAt()的用法 官方解释:Returns the char value at thespecified index. An index ranges from 0 to length() - 1.直白的话:返回字符串中特定下标的字符,从0开始。但有可能出现IndexOutOfBoundsException 异常。

//一个一个的得到expression中的字符,index=0,循环条件index = index + 1
ch = expression.substring(index, index+1).charAt(0);
注意:从String类型的字符串里取出是数字的话,是用Ascii表示的,所以还要转换,相差48

核心的循环代码:

	//开始while循环地扫描expression
		while(true) {
			//依次得到expression中的字符
			 ch = expression.substring(index, index+1).charAt(0);//substring方法从表达式里取出一个,只取出一个字符,但这个字符是在一个数组里的,所以在取出来
			//判断ch,做相应的处理
			 if(operStack.isOper(ch)) {//如果是运算符,就准备入栈
				 //判断当前符号栈是否为空
				 if(!operStack.isEmpty()) {
					 //不为空的话,继续判断
				//如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数。
				//再从符号栈中pop出一个符号,进行运算,将得到的结果,放入数栈。最后才入符号栈
					 if(operStack.priority(ch) <= operStack.priority(operStack.peak())) {
						 //从从数栈中pop出两个数。
						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);	//???? asika表对应关系			 
			 }	
			 //让index+1,并判断是否扫描到expression最后
			 index= index+1;
			 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);			
		}
		System.out.printf("表达式: %s = %d",expression,numStack.pop());
	}

全部的代码:

package com.stack;

public class Calculator {

	public static void main(String[] args) {
		// 完成表达式的计算
		String expression = "90-2*5";
		// 创建两个栈,一个数栈,一个符号栈
		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.substring(index, index + 1).charAt(0);// substring方法从表达式里取出一个,只取出一个字符,但这个字符是在一个数组里的,所以在取出来
			// 判断ch,做相应的处理
			if (operStack.isOper(ch)) {// 如果是运算符,就准备入栈
				// 判断当前符号栈是否为空
				if (!operStack.isEmpty()) {
					// 不为空的话,继续判断
					// 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数。
					// 再从符号栈中pop出一个符号,进行运算,将得到的结果,放入数栈。最后才入符号栈
					if (operStack.priority(ch) <= operStack.priority(operStack.peak())) {
						// 从从数栈中pop出两个数。
						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 {// 如果是数,则直接入数栈
				// 判断是否是多位数
				// 判断下一个字符是否是数字,如果是数字,就继续扫描,如果是运算符,则入栈
				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))) {
						numStack.push(Integer.parseInt(keepNum));
						// 重要的!!!!,清空keepNum
						keepNum = "";
					}
				}
			}
			// 让index+1,并判断是否扫描到expression最后
			index = index + 1;
			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);
		}
		System.out.printf("表达式: %s = %d", expression, numStack.pop());
	}

}

//先创建栈
class ArrayStack2 {

	private int maxsize;// 栈的大小
	private int top = -1;// top表示栈顶,初始化为-1
	private int stack[];// 数组,数组模拟栈,数据就放在该数组

	// 构造器
	public ArrayStack2(int maxsize) {
		// maxsize = this.maxsize;
		this.maxsize = maxsize;
		stack = new int[maxsize];
	}

	// 增加一个方法:可以返回当前栈顶的值,但是不出栈
	public int peak() {
		return stack[top];
	}

	// 栈满
	public boolean isFull() {
		return top == maxsize - 1;
	}

	// 栈空
	public boolean isEmpty() {
		return top == -1;// 栈最开始就是空的,所以当top=-1
	}

	// 入栈
	public void push(int value) {
		// 判断栈是否满
		if (isFull()) {
			System.out.println("栈已经满了,没办法入栈!!");
			return;
		}
		top++;// 要在前面加
		stack[top] = value;
		// top++;不能在后面加
		// System.out.printf("top的值为:%d\n",top);
	}

	// 出栈,将栈顶的数据返回
	public int pop() {
		// 判断栈是否为空
		if (isEmpty()) {
			// System.out.println("栈已经空了,没法出栈了!!");
			// 这里可以输出,也可以写一个异常
			throw new RuntimeException("栈是空的");
		}
		int temp = stack[top];
		top--;
		return temp;
	}

	// 显示栈的情况,是从上到下遍历,从栈顶开始
	public void showStack() {
		//
		if (isEmpty()) {
			System.out.println("栈里为空");
			return;
		}
		for (int i = top; i >= 0; i--) {
			System.out.println(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;// 存储计算的结果

		switch (oper) {
		case '+':
			res = num1 + num2;
			break;
		case '-':
			res = num2 - num1;
			break;
		case '*':
			res = num2 * num1;
			break;

		case '/':
			res = num2 / num1;
			break;

		}
		return res;
	}

}


©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页