前言:
我想了一下,我主要写博客的目标还是说为了自己,自己容易忘记,相当于自己来过一遍,所以这是写给我自己的,当然如果你也遇到了相同的问题,那么不防我们可以一起探讨一下.
表达式求值
一.表达式求值是什么?
表达式就是有加减乘除的式子,与正常的不同,我们这里用的是字符串的形式,来求其答案.
列如:
下面我们将用栈的形式来求其解.
二.表达式求值怎么做?
1.实现原理
对于字符串表达式,我们可以分为左操作数,运算符,右操作数.
我们可以将操作数放入一个栈中,运算符放入另外一个栈中.
然后通过运算符的优先级来进行计算.
计算的时候,我们要先出栈,然后进行计算,然后再将计算的结果入栈进行下次的计算.
2.栈实现
因为要使用栈来装操作数和运算符,那么我们先来创建栈.
可以将其作为头文件,我们需要用的时候引用一下头文件即可.
①.栈结构
用的两个指针来实现,一个分配内存,一个指向栈顶的下一个位置.
②.栈初始化
一个指针分配内存,另外一个指针指向分配好的位置.
③.入栈
在栈顶位置插入值,再移动到下一个位置.
④.出栈
直接对栈顶位置移动到上一个位置.
⑤.获取栈顶元素
栈顶指针减一个位置.
⑥.栈是否为空
如果两指针指向同一个位置则为空.
然后就可以实现我们的栈了,我们先初始化两个栈.
3.左操作数
字符串的第一个数肯定就是左操作数,所以status我们赋值为0.
首先对每个字符串进行循环拿取,isspace可以检验字符串的空格,我们可以跳过.
如果碰到了数字,那么我们可以用字符-'0’可以得到数值.
如果不是一位数的数字,我们需要*10再加上后面的,可以得到我们的操作数.
如果碰到了运算符,那么我们先将刚刚的数值入栈,然后改变状态,i–重新对运算符进行操作.
4.运算符
①.+,-,*,/
遇到第一个运算符不需要做任何操作,只需要入栈,然后改变状态,拿到右操作数.
如果已经不是第一个入栈的运算符了,那么我们需要比较优先级
如果这个运算符的优先级比栈顶的高,那么也只需要入栈就可以了.
因为12+3*6你不可能先算12+3.
如果优先级不高于前一个运算符
那么我们可以取出两操作数和一个运算符进行计算.
将运算的结果还是需要入栈,我们的循环条件是如果运算符栈不为空,同时当前运算符的优先级不高于前一个,那么可以继续进行计算.
如12+36+,36的结果放入栈中因为后面还是加号,还是可以继续进行计算12+18+
当不能进行计算后再将这个符号放入栈中.同时去拿右操作数.
在拿下一个右操作数时,需要将上一次的右操作数清零.
②.=
如果遇到=,那么我们可以出栈进行计算,循环的条件只需要,运算符不为空就可以继续进行计算了.
5.右操作数
与左操作数一样.
6.优先级比较
优先级高于的情况就是一个为*,/同时另一个为+,-,其他情况都是不高于.
7.运算结果
三.完整代码
#include <iostream>
#include "expression.h"
using namespace std;
bool isLarger(const int& lhs, const int& rhs)//rhs栈顶
{
if ((rhs == '+' || rhs == '-') && (lhs == '*' || lhs == '/'))
{
return true;
}
return false;
}
int operate(int left, int right, int op)
{
int result = 0;
cout << "left:" << left << " right:" << right << "op:" << (char)op << endl;
switch (op)
{
case '+':
result = left + right;
break;
case '-':
result = left - right;
break;
case '*':
result = left * right;
break;
case '/':
result = left / right;
break;
default:
break;
}
cout << "result:" << result << endl;
return result;
}
int calculate(string input)
{
SqStack data_stack;//操作数栈
SqStack opt_stack;//运算符栈
int status = 0;//0左操作数,1运算符,2右操作数状态
int ldata = 0;//左操作数值
int rdata = 0;//右操作数值
initStack(data_stack);
initStack(opt_stack);
for (int i = 0; i < input.length(); i++)
{
if (isspace(input[i]))continue;//跳过空格
switch (status)
{
case 0:
if (isdigit(input[i]))//碰到数值
{
ldata *= 10;//在原有的基础上*10
ldata += input[i] - '0';//相加现在的
}
else//碰到操作符
{
cout << "得到左操作数:" << ldata << endl;
PushStack(data_stack, ldata);//操作数入栈
i--;//字符串回退一下
status = 1;//交给操作符的处理
}
break;
case 1:
if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
{
if (isEmpty(opt_stack))//第一个操作符入栈
{
cout << "符号栈为空" << endl;
PushStack(opt_stack, input[i]);//操作符入栈
cout << "符号" << (char)(*GetTop(opt_stack)) << "入栈" << endl;
status = 2;
}
else
{
cout << "isLarger:" << (char)(*GetTop(opt_stack)) << " &" << input[i] << endl;
if (isLarger(input[i], *GetTop(opt_stack)))//当前运算符高于前一个,不能计算前一个运算符
{
cout << "true" << endl;
PushStack(opt_stack, input[i]);//当前运算符入栈
cout << "符号" << (char)input[i] << "入栈" << endl;
status= 2;
rdata = 0;
}
else//当前运算符的优先级不高于前一个运算符,则计算前一个运算符的值
{
int left = 0;
int right = 0;
int opt;
cout << "false" << endl;
do
{
PopStack(data_stack, right);
PopStack(data_stack, left);
PopStack(opt_stack, opt);
cout << "符号" << (char)opt << "出栈" << endl;
cout << "计算前一个运算符" << (char)opt << endl;
int result = operate(left, right, opt);
PushStack(data_stack, result);
} while (!isEmpty(opt_stack)&&!isLarger(input[i],*GetTop(opt_stack)));
PushStack(opt_stack, input[i]);
cout << "符号" << (char)input[i] << "入栈" << endl;
status = 2;
rdata = 0;
}
}
}
else if (input[i] == '=')
{
int opt, result;
do
{
PopStack(data_stack, rdata);
PopStack(data_stack, ldata);
PopStack(opt_stack, opt);
result = operate(ldata, rdata, opt);
PushStack(data_stack, result);
} while (!isEmpty(opt_stack));
return result;
}
else
{
cerr << "输入运算符错误!" << endl;
}
break;
case 2:
if (isdigit(input[i]))//碰到数值
{
rdata *= 10;//在原有的基础上*10
rdata += input[i] - '0';//相加现在的
}
else//碰到操作符
{
cout << "得到右操作数:" << rdata << endl;
PushStack(data_stack, rdata);//操作数入栈
i--;//字符串回退一下
status = 1;//交给操作符的处理
}
break;
default:
break;
}
}
}
int main()
{
string str = "12+3*6/3+4*5=";
cout << calculate(str) << endl;
system("pause");
return 0;
}
列子手绘图:
运行结果: