中缀表达式是通用的算术或逻辑公式表示方法,符合人常规计算的思维.表达式求值的实现方法是栈的一个典型应用.
在计算机中,任何一个表达式都是由操作数,运算符和界限符组成,该篇中仅仅讨论操作数为整型,界限符为各种括号,运算符为加减乘除及其,取余和平方的运算.
根据四则运算的规则:
(1)先括号内,后括号外
(2)先平方,在乘除取余,后加减
(3)同级运算从左到右
举例:{5*3^2+[7+(5-2)]}*3,这个例子可以先不看,先看下面的思路,等回过头来在拿例子来做实验
根据运算规则设置各个运算符的优先级:
'+','-': 0
'*','/','%': 1
'^': 2
'[',']': -1
'(',')': -3
'{','}': -2
计算过程栈区变化表:
序号 | 操作数栈 | 运算符栈 | 注释 |
---|---|---|---|
0 | { | 遇到左括号直接进栈 | |
1 | 5 | { | 遇到操作数直接进栈 |
2 | 5 | { * | 当前指向优先级大入栈 |
3 | 5 3 | { * | 操作数 |
4 | 5 3 | { * ^ | 优先级大入栈 |
5 | 5 3 2 | { * ^ | / |
6 | 5 9 | { * | 当前指向符号优先级小,做计算 |
6 | 45 | { + | 优先级小,计算/优先级大,入栈 |
7 | 45 | { + [ | 左括号入栈 |
8 | 45 7 | { + [ | / |
9 | 45 7 | { + [ + | 优先级大入栈 |
10 | 45 7 | { + [ + ( | 左括号入栈 |
11 | 45 7 5 | { + [ + ( | / |
12 | 45 7 5 | { + [ + ( - | 优先级大入栈 |
13 | 45 7 5 2 | { + [ + ( - | / |
14 | 45 7 3 | { + [ + | 遇到右括号计算 |
15 | 45 10 | { | 遇到右括号计算 |
16 | 55 | 遇到右括号计算 | |
17 | 55 | * | / |
18 | 55 3 | * | / |
19 | 165 |
最终的结果就是165.
index指表达式字符串当前遍历到哪个位置
// 如果为左括号直接进栈
if (isLeft(s.charAt(index))) {
operS.push(s.charAt(index));
index++;
}
// 如果该元素为数字
String number = "";
// 该元素不是括号,不是运算符,则为数字,该篇中如此考虑.
while (!isOper(s.charAt(index)) && !isLeft(s.charAt(index)) && !isRight(s.charAt(index))) {
number += s.charAt(index);
// 为了防止该数字到了表达式的最后一位,所以需要判断一下.否则会进入死循环
if (index == s.length() - 1) break;
index++;
}
if (number != "") {
numS.push(Integer.parseInt(number));
}
// 如果元素为运算符
int num1, num2, oper, res;
// 当算式进行到最后一位时,还要进行一次计算才结束.
if (isOper(s.charAt(index)) || index == s.length() - 1) {
// 如果符号栈为空,元素直接入栈
while (!operS.isEmpty() &&
operS.priority(s.charAt(index)) <= operS.priority(operS.peek()) || !isOper(s.charAt(index))&&!isLeft(s.charAt(index)) && !isRight(s.charAt(index))) {
if (operS.isEmpty()) break;
num1 = numS.pop();
num2 = numS.pop();
oper = operS.pop();
res = campute(num1, num2, oper);
numS.push(res);
}
// 最后一位时为数字,防止他进入符号栈,所以要进行一次判断
if (isOper(s.charAt(index))) {
operS.push(s.charAt(index));
index++;
if (isOper(s.charAt(index))) {
System.out.println("连续的计算符号,错误");
return 99999;
}
}
}
// 如果元素为右括号
if (isRight(s.charAt(index)) && !operS.isEmpty()) {
while (!isLeft(operS.peek())) {
num1 = numS.pop();
num2 = numS.pop();
oper = operS.pop();
res = campute(num1, num2, oper);
numS.push(res);
}
if (operS.priority(s.charAt(index)) == operS.priority(operS.peek())) {
operS.pop(); //弹出栈顶的左括号
index++; //下一位越过当前右括号
} else {
System.out.println("括号匹配错误");
return 99999;
}
}
// 当符号栈为空并且 算式已经进行到结尾时 计算结束
if (operS.isEmpty() && index == s.length() - 1) break;
// 数字栈中最后留下的那一个数字就是最终的结果
return numS.pop();
完整程序,可以自己在修改的简单一些
public class CamputeStackDemo {
public static void main(String[] args) {
String s = "{5^2%3^2+[7+(5+2)]*3}*2";
int i = doCamputee(s);
System.out.println(i);
}
/**
* 主体
* @param s 算式
* @return 最终的结果
*/
public static int doCamputee(String s) {
int index = 0; // 字符串的索引
// 建立两个栈
CamputeStack numS = new CamputeStack(50); // 数字栈
CamputeStack operS = new CamputeStack(50); //符号栈
while (true) {
// 如果为左括号直接进栈
if (isLeft(s.charAt(index))) {
operS.push(s.charAt(index));
index++;
}
// 如果该元素为数字
String number = "";
while (!isOper(s.charAt(index)) && !isLeft(s.charAt(index)) && !isRight(s.charAt(index))) {
number += s.charAt(index);
if (index == s.length() - 1) break;
index++;
}
if (number != "") {
numS.push(Integer.parseInt(number));
}
// 如果元素为计算符号
int num1, num2, oper, res;
// 当算式进行到最后一位时,还要进行一次计算才结束.
if (isOper(s.charAt(index)) || index == s.length() - 1) {
// 如果符号栈为空,元素直接入栈
while (!operS.isEmpty() &&
operS.priority(s.charAt(index)) <= operS.priority(operS.peek()) || !isOper(s.charAt(index))) {
if (operS.isEmpty()) break;
num1 = numS.pop();
num2 = numS.pop();
oper = operS.pop();
res = campute(num1, num2, oper);
numS.push(res);
}
// 最后一位时为数字,防止他进入符号栈,所以要进行一次判断
if (isOper(s.charAt(index))) {
operS.push(s.charAt(index));
index++;
if (isOper(s.charAt(index))) {
System.out.println("连续的计算符号,错误");
return 99999;
}
}
}
// 如果元素为右括号
if (isRight(s.charAt(index)) && !operS.isEmpty()) {
while (!isLeft(operS.peek())) {
num1 = numS.pop();
num2 = numS.pop();
oper = operS.pop();
res = campute(num1, num2, oper);
numS.push(res);
}
if (operS.priority(s.charAt(index)) == operS.priority(operS.peek())) {
operS.pop(); //弹出栈顶的左括号
index++; //下一位越过当前右括号
} else {
System.out.println("括号匹配错误");
return 99999;
}
}
// 当符号栈为空并且 算式已经进行到结尾时 计算结束
if (operS.isEmpty() && index == s.length() - 1) break;
}
// 数字栈中最后留下的那一个数字就是最终的结果
return numS.pop();
}
// 判断元素是否为数字或者为符号
public static boolean isOper(char v) {
if (v == '+' || v == '-' || v == '*' || v == '/' || v=='%' || v=='^') return true;
return false;
}
// 判断是否为左括号
public static boolean isLeft(int v) {
if(v== '(' || v=='[' || v=='{') return true;
return false;
}
// 判断是否为右括号
public static boolean isRight(int v) {
if (v == ')' || v == ']' || v == '}') return true;
return false;
}
// 计算两个数计算的结果
public static int campute(int num1, int num2, int oper) {
int var = 0;
switch (oper) {
case '+': {
var = num1 + num2;
break;
}
case '-': {
var = num2 - num1;
break;
}
case '*': {
var = num2 * num1;
break;
}
case '/': {
var = num2 / num1;
break;
}
case '%':{
var = num2%num1;
break;
}
case '^':{
var = 1;
for(int i = 1 ; i <= num1 ; i++){
var *=num2;
}
break;
}
default: {
System.out.println("该符号不正确");
break;
}
}
return var;
}
}
// 栈的建立
class CamputeStack {
private int maxSize; // 栈的大小
private int[] stack; // 栈
private int top = -1; //定义栈顶
// 初始化栈
public CamputeStack(int maxSize) {
this.maxSize = maxSize;
stack = new int[maxSize];
}
// 判断栈是否为空
public boolean isEmpty() {
return top == -1;
}
// 判断栈是否为满
public boolean isFull() {
return top == maxSize - 1;
}
// 入栈
public void push(int v) {
if (isFull()) {
System.out.println("栈满");
return;
}
top++;
stack[top] = v;
}
// 出栈
public int pop() {
if (isEmpty()) {
System.out.println("栈空");
throw new RuntimeException("栈空");
}
int v = stack[top];
top--;
return v;
}
// 查看栈顶元素
public int peek() {
if (isEmpty()) {
System.out.println("栈空");
throw new RuntimeException("栈空");
}
return stack[top];
}
// 返回元素的优先级
public int priority(int oper) {
int val = 100;
switch (oper) {
case '*':
case '%':
case '/': {
val = 1;
break;
}
case '^':{
val = 2;
break;
}
case '+':
case '-': {
val = 0;
break;
}
case '[':
case ']': {
val = -1;
break;
}
case '{':
case '}': {
val = -2;
break;
}
case '(':
case ')': {
val = -3;
break;
}
}
return val;
}
}
此篇到此就结束了,大家生活愉快-^^-!!!