一、算符优先法
前提
算符优先法需要设立两个栈。(本来不应该是这两个单词,但是本教主觉得更加重要的是命名的易区分性)
- 寄存操作数的栈
nums
- 寄存操作符的栈
opters
基本思想
-
首先置
nums
栈为空,表达式起始符#
为opters
栈的栈底元素 -
依次读入表达式中的每个字符,用
isOpters()
判断是否是操作数-
如果是操作数则进
nums
栈 -
如果是操作符,则将栈顶元素和该操作符比较优先级(栈顶操作符和该操作符比较优先级)循环进行直到读取到截断符号
#
- 若栈顶操作符优先级低,则将该操作符入栈
- 如果相等,那么就说明是括号,成对消去(弹出栈中的左括号即可)
- 如果栈顶操作符优先级高,则说明栈顶的操作符就是目前需要参与运算的运算符。
-
更简单的后缀表示法
- 只需一个操作数栈
- 将中缀表达式转换为后缀表达式,因为计算机更擅长于处理后缀表达式。(参考博客中缀表达式转后缀表达式(c++))
- 操作数栈弹出两个操作数,和剩下的操作符参与运算
二、源码
caculate.h
文件
-
相比较从黑窗口读取缓存区的字符,直接处理字符串的情况显得更加大众一点儿,所以选择了将中缀表达式存放在字符串中。
-
string
类重载了[]
符号,因而可以像字符数组一样直接使用str[i]
来获取string
对象的第i个位置的字符。 -
将表示
int
的char
型转换为int
型,最常用的办法是利用ASCII表,直接减去'\0'
的ASCII值48就可以获取对应的int
值。
#pragma once
#ifndef caculate_H
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;
//算符优先法
class Caculate {
public:
static const char ERROR = 'E';
stack<int> nums; //操作数栈
stack<char> opters; //操作符栈
string expression; //中缀表达式
public:
Caculate(string expression) {
this->expression = expression;
}
//计算结果
public:
int caculate() {
int i = 0; //用来读取下一位的位置指针
//1.将 # 入栈
opters.push('#');
while (expression[i] != '#' || opters.top() != '#') {
//2.如果是操作数,则入栈
if (!this->isOpters(expression[i])) {
nums.push(expression[i] - 48);
i++;
}
//3.如果是操作符,则与栈顶符号比较优先级,来决定是否计算
else if (this->isOpters(expression[i])) {
switch (this->compare(opters.top(), expression[i])) {
case '<': //栈顶元素优先级低:符号入栈
opters.push(expression[i]);
i++;
break;
case '=': //优先级相等:说明是栈顶的 ( 和 expression的 ),则消去一对括号
opters.pop();
i++;
break;
case '>': //栈顶元素优先级高:计算并将计算结果入栈
int opval2 = nums.top();
nums.pop();
int opval1 = nums.top();
nums.pop();
//将计算结果入栈
int result = this->caculate(opval1, opters.top(), opval2);
nums.push(result);
//弹出运算符
opters.pop();
break;
}
}
}
//4.计算完后返回栈顶元素
return nums.top();
}
//计算两个数的结果
public:
int caculate(int a, char opters, int b) {
if (opters == '+') {
return a + b;
} else if (opters == '-') {
return a - b;
} else if (opters == '*') {
return a * b;
} else if (opters == '/') {
return a / b;
} else {
cout << "操作符有误!";
return 0;
}
}
//判断是否是操作符
public:
bool isOpters(char opters) {
return (opters == '+' ||
opters == '-' ||
opters == '*' ||
opters == '/' ||
opters == '(' ||
opters == ')' ||
opters == '#') ? true : false;
}
//比较操作符的优先级
public:
char compare(char op1, char op2) {
if (op1 == '+' || op1 == '-') {
if (op2 == '+' || op2 == '-' || op2 == ')' || op2 == '#') {
return '>';
} else {
return '<';
}
} else if (op1 == '*' || op1 == '/') {
if (op2 == '(') {
return '<';
} else {
return '>';
}
} else if (op1 == '(') {
if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == '(') {
return '<';
} else if (op2 == ')') {
return '=';
} else {
cout << "输入有误";
return ERROR;
}
} else if (op1 == ')') {
if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == ')' || op2 == '#') {
return 1;
} else if (op2 == '(') {
cout << "输入有误";
return ERROR;
}
} else if (op1 == '#') {
if (op2 == ')') {
cout << "输入有误";
return ERROR;
} else if (op2 == '#') {
return 0;
} else {
return '<';
}
}
}
};
#endif // !caculate_H
算符间的优先关系
//比较操作符的优先级
public:
char compare(char op1, char op2) {
if (op1 == '+' || op1 == '-') {
if (op2 == '+' || op2 == '-' || op2 == ')' || op2 == '#') {
return '>';
} else {
return '<';
}
} else if (op1 == '*' || op1 == '/') {
if (op2 == '(') {
return '<';
} else {
return '>';
}
} else if (op1 == '(') {
if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == '(') {
return '<';
} else if (op2 == ')') {
return '=';
} else {
cout << "输入有误";
return ERROR;
}
} else if (op1 == ')') {
if (op2 == '+' || op2 == '-' || op2 == '*' || op2 == '/' || op2 == ')' || op2 == '#') {
return 1;
} else if (op2 == '(') {
cout << "输入有误";
return ERROR;
}
} else if (op1 == '#') {
if (op2 == ')') {
cout << "输入有误";
return ERROR;
} else if (op2 == '#') {
return 0;
} else {
return '<';
}
}
}
main.cpp
文件
#include<iostream>
#include"caculate.h"
using namespace std;
int main() {
Caculate c("3*(7-2)#");
int m = c.caculate();
cout << m << endl;
}