中缀式、后缀式、前缀式的定义
中缀式
是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
后缀式
逆波兰式,这种表示方式把运算符写在运算对象的后面,例如,把a+b写成ab+,所以也称为后缀式。这种表示法的优点是根据运算对象和算符的出现次序进行计算,不需要使用括号,也便于用械实现求值。
前缀式
波兰式,前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。例如,- 1 + 2 3,它等价于1-(2+3)。
中缀式转化为后缀式、前缀式
中缀式转化为后缀式
方法一 :二叉树法
中缀式可以通过构造二叉树,并且后序遍历二叉树的方法求得后缀式,方法如下:
- 找到中缀式中最后运算的运算符作为二叉树的根节点;
- 将1中运算符左右两边的式子分别构造二叉树作为1中节点 的左右子树。如果式子中只剩下一个操作数,则将操作数作为叶子节点,如果式子中含有操作数和运算符,则利用1、2讲述的方法继续往下生成左右子树。直到所有叶节点均为操作数为止;
- 将得到的二叉树进行后序遍历即可得到原中缀式的后缀式。
以中缀式 (1+2) * 3+2 * 1 为例示意图如下:
后序遍历该二叉树可得后缀式为 1 2 + 3 * 2 1 * +
方法二:利用栈
- 构造一个栈stk;
- 从左往右扫描中缀式,如果遇到操作数则直接输出;如果遇到‘(’,则将‘(’压入栈;如果遇到),则将栈stk中操作符依次出栈并输出,直到‘(’为止,【注释:‘(’只出栈,不输出】;如果遇到运算符,则将栈stk中操作符依次出栈并输出,直到‘(’或者优先级小于当前操作符为止,然后将当前操作符压入栈stk中;
- 当扫描结束时,如果stk不空,则将stk中的操作符依次出栈并输出。
对于该方法,可通过南阳理工OJ的题目来说明,题目如下:
痞子的实现代码如下:
#include<iostream>
#include<stdio.h>
#include<stack>
#include<string>
using namespace std;
int compare_1(char a,char b)
{
//默认只比较加减乘除
if(a=='+' || a=='-')
{
if(b=='+' || b=='-')
{
return 1;
}
else
{
return 0;
}
}
else
{
return 1;
}
}
int main()
{
int n;
string s;//s存放读入的字符串(中缀式),
cin>>n;
while(n--)
{
cin>>s;
stack<char> stk;//存放操作符
int len=s.length();
int i;
int c;
//int flag=0;
for(i=0;i<len-1;i++)
{
if((s[i]>='0' && s[i]<='9') || s[i]=='.')//如果是数字则直接输出
{
if((s[i+1]>='0' && s[i+1]<='9') || s[i+1]=='.')
{
printf("%c",s[i]);
}
else
{
printf("%c ",s[i]);
}
}
else if(s[i]=='(')//如果是(则入栈
{
stk.push('(');
}
else if(s[i]==')')//如果是)则将栈中第一个( 前的操作符都出栈输出,(出栈不输出
{
c=stk.top();
while(c!='(')
{
printf("%c ",c);
stk.pop();
c=stk.top();
}
stk.pop();
}
else
{
if(stk.empty())//如果栈中为空,则直接入栈
{
stk.push(s[i]);
}
else
{
while(!stk.empty() &&(c=stk.top())!='(' && compare_1(c,s[i]))
{
printf("%c ",c);
stk.pop();
}
stk.push(s[i]);
}
}
}
while(!stk.empty())
{
c=stk.top();
printf("%c ",c);
stk.pop();
}
printf("=\n");
}
return 1;
}
中缀式转前缀式
方法一:二叉树法
- 构造二叉树的方法与求后缀式的方法相同;
- 将生成的二叉树进行先序遍历即可得到前缀式。
求得前缀形式为 + * + 1 2 3 * 2 1
方法二:利用栈
- 构造一个栈stk;
- 从右往左扫描中缀式,如果遇到操作数则直接输出;如果遇到‘)’,则将‘)’压入栈;如果遇到‘(’,则将栈stk中操作符依次出栈并输出,直到‘)’为止,【注释:‘)’只出栈,不输出】;如果遇到运算符,则将栈stk中操作符依次出栈并输出,直到‘)’或者优先级小于当前操作符为止,然后将当前操作符压入栈stk中;
- 当扫描结束时,如果stk不空,则将stk中的操作符依次出栈并输出。
将中缀式转化为后缀式求值
先叙述一下方法:
1.将中缀式s转化为后缀式stk;
2.创建栈stk用于存放操作数;
3.从左到右扫描后缀式stk,遇到操作数则压入栈;遇到运算符则弹出栈stk的最上面的上个元素a,b,利用当前运算符对a,b进行运算,将结果压入栈stk中;
4.扫描结束,留在栈stk中的数即为运算结果。
同样,也借助于南阳理工OJ的题目来说明
题目如下:
痞子的AC代码如下:
#include<iostream>
#include<stdio.h>
#include<stack>
#include<string>
#include <stdlib.h>
#include <sstream>
using namespace std;
int compare(char a,char b)
{
//默认只比较加减乘除
if(a=='+' || a=='-')
{
if(b=='+' || b=='-')
{
return 1;
}
else
{
return 0;
}
}
else
{
return 1;
}
}
string trans(string s)
{
stack<char> stk;//存放操作符
int len=s.length();
int i;
char c;
string str="";
//int flag=0;
for(i=0;i<len-1;i++)
{
if((s[i]>='0' && s[i]<='9') || s[i]=='.')//如果是数字则直接输出
{
if((s[i+1]>='0' && s[i+1]<='9') || s[i+1]=='.')
{
str=str+s[i];
}
else
{
str=str+s[i]+' ';
}
}
else if(s[i]=='(')//如果是(则入栈
{
stk.push('(');
}
else if(s[i]==')')//如果是)则将栈中第一个( 前的操作符都出栈输出,(出栈不输出
{
c=stk.top();
while(c!='(')
{
str=str+c+' ';
stk.pop();
c=stk.top();
}
stk.pop();
}
else
{
if(stk.empty())//如果栈中为空,则直接入栈
{
stk.push(s[i]);
}
else
{
while(!stk.empty() &&(c=stk.top())!='(' && compare(c,s[i]))
{
str=str+c+' ';
stk.pop();
}
stk.push(s[i]);
}
}
}
while(!stk.empty())
{
c=stk.top();
str=str + c +' ';
stk.pop();
}
str=str+'=';
return str;
//return 1;
}
double stf(string s)
{
istringstream iss(s);
double num;
iss >> num;
return num;
//return atof(s);
}
double oper(double a,double b,char c)
{
if(c=='+')
{
return a+b;
}
else if(c=='-')
{
return a-b;
}
else if(c=='*')
{
return a*b;
}
else
{
return 1.0*a/b;
}
}
int main()
{
int n;
string s,str,num="";
cin>>n;
double a,b;
while(n--)
{
cin>>s;
str=trans(s);
stack <double> stk;
int len=str.length();
int i;
num="";
for(i=0;i<len-1;i++)
{
if(str[i]==' ')
{
if(num!="")
{
stk.push(stf(num));
num="";
}
}
else if((str[i]>='0' && str[i]<='9') || str[i]=='.')
{
num=num+str[i];
}
else
{
double a=stk.top();
stk.pop();
double b=stk.top();
stk.pop();
stk.push(oper(b,a,str[i]));
}
}
printf("%.2f\n",stk.top());
}
return 1;
}
代码写的有点乱,见谅!
最后,如文中出现错误,欢迎指正,痞子将及时修改,谢谢!