提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容:
我们再来重点讲 个比较常见的应用:数学达式的求值。20世纪50年代,波兰逻辑学家Jan Lukasiewicz,当时也和我们现在的同学们一样,困惑于如何才可以搞定这个四则运算,不知道他是否也像牛顿被苹果砸到头而想到万有引力的原理,或者还是阿基米德在浴缸中洗澡时想到判断皇冠是否纯金的办法,总之他也是灵感突现,想到了一种不需要括号的后缀表达法,我们也把它称为**逆波兰(Reverse Polish Notation,RPN)**表示。我想可能是他的名字太复杂了,所以后人只用他的国籍而不是姓名来命名,实在可惜。这也告诉我们,想要流芳百世,名字还要起得朗朗上口才行。
码字不易,有问题可以一起学习讨论,一起进步,动动小手三连哦!!!
提示:以下是本篇文章正文内容,下面案例可供参考
一、后缀表示法
这种后缀表示法,是表达式的一种新的显示方式,非常巧妙地解决了程序实现四则运算的难题。
我们先来看看,对于“9+(3-1)×3+10÷2”,如果要用后缀表示法应该是什么样子:“9 3 1-3*+10 2/ +”,这样的表达式称为后缀表达式,叫后缀的原因在于所有的符号都是在要运算数字的后面出现。显然,这里没有了括号。对弈从来没有接触过后缀表达式的同学来讲,这样的表述是很难受的。不过你不喜欢,有机器喜欢,比如比我们聪明的计算机。
二、实现过程解析
后缀表达式:9 3 1 - 3 * + 10 2 / +
规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果出栈,一直到最终获得结果。
1.初始化一个空栈,用于对要运算的数字进出使用。
2.后缀表达式中前三个都是数字,所以9、3、1进栈。
3.接下来是“一”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再将2进栈。接着是数字3进栈,如图所示。
4.后面是“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。下面是“+”,所以栈中6和9出栈,9与6相加,得到15,将15进栈,如图所示。
5.接着是10与2两数字进栈。接下来是符号“/”,因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈,如图所示。
6.最后一个是符号“+”,所以15与5出栈并相加,得到20,将20进栈。结果是20出栈,栈变为空,如图所示。
果然,后缀表达法可以很顺利解决计算的问题。现在除了还没睡醒的小伙伴,应该都有同样的疑问,就是这个后缀表达式“9 3 1 - 3 * + 10 2 / +”是怎么出来的?这个问题不搞清楚,等于没有解决。所以下面,我们就来推导如何让“9+(3-1)×3+10÷2”转化为“9 3 1 - 3 * + 10 2 / +”。
三、中缀表达式转后缀表达式
中缀表达式“9 + (3 - 1) × 3 + 10 ÷ 2”转化为后缀表达式“9 3 1 - 3 * + 10 2 / +”。
规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
1.初始化一空栈,用于对符号进出栈使用。第一个字符是数字9 ,输出9 ,后面是符号"+",进栈。
2.第三个字符是“(”,依然是符号,因其只是左括号,还未配对,故进栈。第四个字符是数字3,输出,总表达式为9 3,接着是“一”,进栈。
3.接下来是数字1,输出,总表达式为9 3 1,后面是符号“)”,此时,我们需要去匹配此前的“(”,所以栈顶依次出栈,并输出,直到“(”出栈为止。此时左括号上方只有“-”,因此输出“-”。总的输出表达式为9 3 1 -。接着是数字3,输出,总的表达式为9 3 1 - 3。紧接着是符号“×”,因为此时的栈顶符号为“+”号,优先级低于“×”,因此不输出,“”进栈。
4. 之后是符号“+”,此时当前栈顶元素“”比这个“+”的优先级高,因此栈中元素出栈并输出(没有比“+”号更低的优先级,所以全部出栈),总输出表达式为931-3*+。然后将当前这个符号“+”进栈。也就是说,前6张图的栈底的“+”是指中缀表达式中开头的9后面那个“+”,而下图中的栈底(也是栈顶)的“+”是指“9+(3-1)×3+”中的最后一个“+”。紧接着数字10,输出,总表达式变为931-3*+10。后是符号“÷”,所以“/”进栈。
5.最后一个数字2,输出,总的表达式为9 3 1-3*+10 2。如图4-9-10的左图所示。.因已经到最后,所以将栈中符号全部出栈并输出。最终输出的后缀表达式结果为9 3 1 - 3 * + 10 2 / +。
四、Python和VC中缀表达式转后缀表达式实例代码
#python代码实例
def middle2behind(expresssion): #中缀表达式转后缀表达式
#只支持整数
result = [] # 结果列表
stack = [] # 栈
i = 0 #表达式索引
expresssion = list(expresssion)
expresssion.append('$') #添加结尾标识符
while(1):
if expresssion[0] == '$':
break
elif '.'.join(expresssion[:-1]).isdigit():
result.apppend(int('.'.join(expresssion[:-1])))
break
item = expresssion[i]
step = 1
while (item.isdigit()) and \
(expresssion[i+step] in "0123456789"):
item += expresssion[i+step]
step +=1
# print(char, stack)
# if len(stack)!=0:
# print(stack[-1], stack[-1] in '+-*/((')
if (item.isdigit()) and \
((len(stack)==0) or (stack[-1] in '+-*/((')):
# print(11111)
i+=step
result.append(item)
# stack.pop()
# stack.append(item)
# break
elif (item in "((") and \
((len(stack)==0) or (stack[-1] in '+-*/((')):
# print(22222)
i+=step
# result.append(item)
# stack.pop()
stack.append(item)
# break
elif (item in "+-") and \
((len(stack)!=0) and (stack[-1] in '+-')):
# print(33333)
i+=step
result.append(stack.pop())
stack.append(item)
# break
elif (item in "*/") and \
((len(stack)!=0) and (stack[-1] in '+-')):
# print(44444)
i+=step
# result.append(item)
# stack.pop()
stack.append(item)
# break
elif (item in "+-*/") and \
((len(stack)!=0) and (stack[-1] in '*/')):
# print(55555)
i+=step
result.append(stack.pop())
stack.append(item)
# break
elif (item in "+-*/") and \
((len(stack)==0) or (stack[-1] in '((')):
# print(66666)
i+=step
# result.append(stack.pop())
stack.append(item)
# break
elif (item in "))") and \
((len(stack)!=0) and (stack[-1] in '((')):
# print(77777)
i+=step
# result.append(item)
stack.pop()
# stack.append(item)
# break
elif (item in "))$") and \
((len(stack)!=0) and (stack[-1] in '+-*/')):
# print(88888)
# i+=step
result.append(stack.pop())
# stack.append(item)
# break
elif (item in "$") and \
(len(stack)==0):
# print(99999)
# i+=1step
# result.append(stack.pop())
# stack.append(item)
break
else:
# print('******')
result.append('*****') #表达式不符合要求,解析异常
break
# 返回字符串
return result
def calculation(postfixExpr): #计算后缀表达式
stack = []
if len(postfixExpr) == 1:
return int(postfixExpr[0])
for item in postfixExpr:
if item.isdigit():
stack.append(int(item))
else:
operand2 =stack.pop()
operand1 =stack.pop()
result =doMath(item,operand1,operand2)
stack.append(result)
return stack.pop()
def doMath(op, op1, op2):
if op == "*":
return op1 * op2
elif op == "/":
return op1 / op2
elif op == "+":
return op1 + op2
else:
return op1 - op2
#####使用代码实例##############使用代码实例###################使用代码实例##################
expression = "((((1000+2000))-2000)*(40+60))/10000"
postfixExpr = middle2behind(expression)
postfixExpr
if '*****' not in postfixExpr:
print(calculation(middle2behind(expression)))
else:
print('表达式解析错误')
### 输出结果:10
// vc 代码实例
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
int priority(char op) // 优先级确认
{
int priority;
if(op == '*' || op == '/') priority = 2;
if(op == '+' || op == '-') priority = 1;
if(op == '(') priority = 0;
return priority;
}
// 转换函数,引用符号提高转换效率
void Trans(string &str, string &str1)
{
stack<char> s;
int i;
for(i = 0; i < str.size(); i ++ )
{
//是数字的情况下直接输出
if(str[i] >= '0' && str[i] <= '9' || str[i] >= 'a' && str[i] <= 'z')
{
str1 += str[i];
}
else //不是数字的情况分类讨论进行判断
{
//栈为空时直接入栈
if(s.empty()) s.push(str[i]);
//左括号入栈
else if(str[i] == '(') s.push(str[i]);
//如果是右括号,只要栈顶不是左括号,就弹出并输出
else if(str[i] == ')')
{
while(s.top() != '(')
{
str1 += s.top();
s.pop();
}
//弹出左括号,但不输出
s.pop();
}
else
{
//栈顶元素的优先级大于等于当前的运算符,就将其输出
while(priority(str[i]) <= priorty(s.top()))
{
str1 += s.top();
s.pop();
//栈为空,停止
if(s.empty()) break;
}
s.push(str[i]);
}
}
}
//最后,如果不为空,就把所以的元素全部弹出
while(!s.empty())
{
str1 += s.top();
s.pop();
}
}
int main()
{
//输入前缀表达式
string infix;
string postfix;
cin >> infix;
Trans(infix, postfix);
cout << postfix << endl;
return 0;
}
总结
从刚才的推导中你会发现,要想让计算机具有处理我们通常的标准(中缀)表达式的能力,最重要的就是两步:
1.将中缀表达式转化为后缀表达式(栈用来进出运算的符号)。
2.将后缀表达式进行运算得出结果(栈用来进出运算的数字)。
码字不易,有问题可以一起学习讨论,一起进步,动动小手三连哦!!!