【算法】栈实现表达式求值(C++)(详解)
【栈】实现表达式求值
思路 && 理解 && 注意
给定一串表达式,字符串类型,依次遍历从头开始遍历每一个位置的内容。
第一个数字,第一个运算符先直接往栈里面push(两个不同的栈) 接着走,遇到数push进来,接着走,遇到运算符,和前面那个已经push进栈的运算符进行优先级比较,如果当前运算符优先级大,那就接着push进来,反之,pop出栈,运算前面的式子之和(之后判断运算符栈中是否还有内容,并且当前运算符的优先级是否小于等于已有的运算符,小于等于就接着运算前面的表达式,完成push当前运算符,反之继续往下遍历push...pop...),直到最后一个元素。
注意;
一直发生变化的是rdata-右操作数,所以每次压完运算符找新的右操作数都会将他置空,准备重新赋值。
没有添加括号优先级运算。
expression.h
#pragma once
#include<iostream>
using namespace std;
#define MAX_SIZE 128
typedef struct _Postion//地图中点的坐标,这个栈中存的元素就是点的坐标
{
int _x;
int _y;
}Postion;
typedef int DataType;
//栈的结构体
typedef struct _Stack
{
DataType* top;
DataType* base;
}Stack;
//栈的初始化
bool initStack(Stack& S)
{
S.base = new DataType[MAX_SIZE];
if (!S.base)
{
return false;
}
S.top = S.base;
return true;
}
//入栈
bool pushStack(Stack& S, DataType data)
{
if (!S.base)
{
return false;
}
if (S.top - S.base == MAX_SIZE)
{
return false;
}
*(S.top) = data;
S.top++;
return true;
}
//出栈
bool popStack(Stack& S, DataType& e)
{
if (S.top == S.base)
{
return false;
}
e = *(--S.top);
return true;
}
//返回栈顶元素
DataType* getTop(Stack& S)
{
if (S.top - S.base == 0)
{
return NULL;
}
//注意何时自增何时不自增
return S.top - 1;//返回栈顶元素的指针
}
//返回栈中元素个数
int getSize(Stack& S)
{
return S.top - S.base;
}
//判断栈是否为空
bool isEmpty(Stack& S)
{
if (S.top == S.base)
{
return true;
}
else
{
return false;
}
}
//销毁栈
void destoryStack(Stack& S)
{
if (S.base)
{
delete[] S.base;
S.top = S.base = NULL;
}
}
experssion.cpp
#include"expression.h"
#include<iostream>
using namespace std;
//比较 lhs 的优先级是否高于 rhs,rhs 表示栈顶的符号
bool isLarger(const int &lhs, const int &rhs)
{
if ((rhs == '+' || rhs == '-') && (lhs == '*' || lhs == '/'))
{
return true;
}
return false;
}
//计算左右操作数+运算符 (对运算符求值)
int operate(int left, int right, int op)
{
int result = 0;
switch (op)
{
case '+':
result = left + right;
break;
case '-':
result = left - right;
break;
case '*':
result = left * right;
break;
case '/':
result = left / right;
break;
default:
break;
}
return result;
}
//运算主体
int calculate(string input)
{
Stack data_stack;//操作数堆栈
Stack opt_stack;//运算符堆栈
int status = 0;//0接收左操作数,1接收操作符,2,接收右操作数
//左右操作数
//一直在发生变化的是右操作符
int ldata = 0;
int rdata = 0;
char last_opt = '\0';
//初始化堆栈
initStack(data_stack);
initStack(opt_stack);
//从第一个开始遍历
for (int i = 0; i < input.length(); i++)
{
if (isspace(input[i]))//跳过空白符
{
continue;
}
//不是空白,第一次到这里,默认是status = 0是左操作数
switch (status)
{
//isdigit-判断是否是十进制数字
case 0:
//得到做操作数左操作数
/*
左操作数是如何得到的
遍历字符串,第一个得到的肯定是左操作数,但我们不知道它是几位数。默认ldata为0
其实就是——这个数是几位,这个if()条件就能进来几次
累加在ldata中,得到左操作数
*/
if (isdigit(input[i]))
{
ldata *= 10;
ldata += input[i] - '0';//求出该位上这个数是几
}
//什么时候执行到这里?
//第一个数字得到之后,也就是得到了ldata之后
else
{
pushStack(data_stack, ldata);//左操作数进栈
//现在input[i]的位置是运算符
//因为结束case结束之后,出来for循环还得++,这样就错过这个运算符了
//为了保证到case 1的语句中此时的input[i]是运算符,所以要字先--
i--;
status = 1;//操作数确定了,下一个就该运算符了。
}
break;
case 1://遇到操作符
if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
{
if (isEmpty(opt_stack))//第一个运算符暂时不做任何处理,先入栈保存
{
pushStack(opt_stack, input[i]);//第一个操作符进栈
//运算符进栈存的是对应符号的ASCII码
status = 2;//状态标记为2 下一个为右操作数
}
else//不是第一个运算符,那么就将这个与之前的做优先级比较,如果这个优先级高,那就先算这个
{
//当前运算符高于前一个运算符
//当前input[i]运算符 栈里面的存的第一个运算符
if (isLarger(input[i], *getTop(opt_stack)))//如果当前运算符的优先级高于前一个
{
//压进栈
pushStack(opt_stack, input[i]);//操作符入栈
status = 2;//下一个是右操作数
rdata = 0;//将右操作数置空
}
else//当前运算符的优先级小于(等于)前一个(栈顶)运算符。则计算前一个运算符的值
{
int right = 0;
int left = 0;
int opt = 0;
do
{
//拿到操作符 和 前面两个左右操作数
//先取到右边的,在取左边的(倒着拿出来)
//运算的时候注意参数传递顺序
popStack(data_stack, right);
popStack(data_stack, left);
popStack(opt_stack, opt);
int result = operate(left, right, opt);
pushStack(data_stack, result);//得到一部分的结果压进栈
} while (!isEmpty(opt_stack) && !isLarger(input[i],*getTop(opt_stack)));//自动再往前判断,是否可以对前面的表达式进行运算
//运算符栈不为空 并且当前运算符优先级小于等于栈顶运算符(前面的)那么就能一并进行运算
//将当前input[i]运算符压入栈
pushStack(opt_stack, input[i]);
status = 2;//去右操作数
rdata = 0;//置空
}
}
}
else if (input[i] == '=')//到达结尾
{
int opt = 0;
int result = 0;
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右操作数
{
rdata *= 10;
rdata += input[i] - '0';
}
else
{
pushStack(data_stack, rdata);//右操作数入栈
i--;
status = 1;
}
break;
}
}
return -1;
}
int main(void)
{
string str = "12+3*6/3+4*5=";
cout << calculate(str) << endl;//38
return 0;
}