简单计算机——逆波兰表达式
逆波兰数:逆波兰数由两部分组成(操作数,操作符)——是波兰表达式的一种,即操作符在操作数的后面。
形式:A+B*C-D = ABC*D-;
(A+B)*C-D = AB+C*D-;
既然我们知道了,后缀表达式那我们表达式是唯一的吗?我们来看一组数据:
例如:(A+B)*C-D 和 C*(A+B)-D;
很显然第二个的表达式为:C*AB+D-;虽然对最后的结果无影响,但我们需要知道逆波兰的多样性。
注意事项:
1、如果出现1+23 = 123+,该如何判断它的数值呢?
可以利用分割符来进行很好的辅助性理解,例如1+23 = 1#23#+,这样可以完美的解决此问题。
2、存在括号的时候该如何处理?
其一:是‘(’直接压入,‘)’时,将两者之间的运算符弹出,压入后缀表达式。
其二:遇到‘(’开辟一个新的运算符栈,‘)’时,当前栈内运算符弹出,压入后缀表达式。
算法:
1、中缀表达式——逆波兰表达式的转变。
- 准备一个栈一个链表,链表用来存操作数,栈用来存操作符。
- 如果为操作数,我们继续判断它的下一位是否也为操作数,是——则继续压入,否——压入分隔符(“#”)。同时判断字符栈中,是否为“*”,“/”,字符弹出,压入数值链表。
- 如果为操作符,直接压入字符栈。
- 如果‘(’,重新开辟一个新字符栈,其它操作相同。
- 如果‘ )’,将当前字符栈内部的字符逐个弹出,压入数值链表。
2、逆波兰求值。
- 准备一个栈,用来逐个求当前值。
- 依次取出数值链表的第一个值。
- 根据加减乘除运算做出相应的操作,即取出当前栈的前两个值,做运算符操作。
- 如果是操作数,我们继续判断它的下一位是否也为操作数,是——n*10+char-‘0’,否——压入栈中;
- 最后的到栈顶元素,即为运算后的值。
核心代码:
1、中缀表达式——逆波兰表达式的转变。
bool is_char(char c)//判断是否为操作符
{
return c == '-' || c == '+' || c == '*' || c == '/';
}
void change()//表达式的转化
{
char c;
int i = 0, j = 0;//i遍历输入的字符,j不同层数的字符栈
while ((c = original[i++]) != '\0')
{
if (is_char(c))//是字符
one[j].push(c);
else if (is_number(c))//是数字
{
int x = i;//
while (is_number(c))
{
sconed.push_back(c);
if (is_number(c = original[x++]))//是数值,则数组往后移动一位(确保下一步能读取字符)
i++;
}
sconed.push_back('#');//分隔符
if (!one[j].empty())//判断是否为空
if (one[j].top() == '*' || one[j].top() == '/')//高阶运算,直接取出,压入数值链表
{
sconed.push_back(one[j].top());
one[j].pop();
}
}
else if (c == ')')
{
Dum(j);//多余的运算符赋值
j--;//回到上一层的字符栈
}
else
j++;//新的字符栈
}
Dum(j);
}
void Dum(int j)//多余的运算符逐个压入数值链表
{
while (!one[j].empty())
{
sconed.push_back(one[j].top());
one[j].pop();
}
}
2、逆波兰求值。
void Do_it(std::stack<int> &mc)
{
while (!sconed.empty())//不为空时。
{
char mid = sconed.front();//临时存储字符
sconed.pop_front();//压出
switch (mid)//判断
{
int a, b;
case'-':
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行减法运算。
mc.push(a - b);
break;
case'+':
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行加法运算。
mc.push(a + b);
break;
case'*':
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行乘法运算。
mc.push(a * b);
break;
case'/':
b = mc.top(), mc.pop(), a = mc.top(), mc.pop();//得到前两个数值进行除法运算。
if (b == 0)//分母不能位0
{
is_right = false;
return;
}
else
mc.push(a / b);
break;
default://获得数值
{
int sum = 0;
if (is_number(mid))
{
while (is_number(mid))
{
sum = sum * 10 + mid - '0';//字符到数字的改变
mid = sconed.front();
if (is_number(mid))
sconed.pop_front();
}
mc.push(sum);
}
}
}
}
}
3、GitHub源码;