中缀式、前缀式、后缀式相关

中缀式、后缀式、前缀式的定义

中缀式

是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。

后缀式

逆波兰式,这种表示方式把运算符写在运算对象的后面,例如,把a+b写成ab+,所以也称为后缀式。这种表示法的优点是根据运算对象和算符的出现次序进行计算,不需要使用括号,也便于用械实现求值。

前缀式

波兰式,前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。例如,- 1 + 2 3,它等价于1-(2+3)。

中缀式转化为后缀式、前缀式

中缀式转化为后缀式

方法一 :二叉树法

中缀式可以通过构造二叉树,并且后序遍历二叉树的方法求得后缀式,方法如下:

  1. 找到中缀式中最后运算的运算符作为二叉树的根节点;
  2. 将1中运算符左右两边的式子分别构造二叉树作为1中节点 的左右子树。如果式子中只剩下一个操作数,则将操作数作为叶子节点,如果式子中含有操作数和运算符,则利用1、2讲述的方法继续往下生成左右子树。直到所有叶节点均为操作数为止;
  3. 将得到的二叉树进行后序遍历即可得到原中缀式的后缀式。

以中缀式 (1+2) * 3+2 * 1 为例示意图如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
后序遍历该二叉树可得后缀式为 1 2 + 3 * 2 1 * +

方法二:利用栈

  1. 构造一个栈stk;
  2. 从左往右扫描中缀式,如果遇到操作数则直接输出;如果遇到‘(’,则将‘(’压入栈;如果遇到),则将栈stk中操作符依次出栈并输出,直到‘(’为止,【注释:‘(’只出栈,不输出】;如果遇到运算符,则将栈stk中操作符依次出栈并输出,直到‘(’或者优先级小于当前操作符为止,然后将当前操作符压入栈stk中;
  3. 当扫描结束时,如果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. 将生成的二叉树进行先序遍历即可得到前缀式。

求得前缀形式为 + * + 1 2 3 * 2 1

方法二:利用栈

  1. 构造一个栈stk;
  2. 从右往左扫描中缀式,如果遇到操作数则直接输出;如果遇到‘)’,则将‘)’压入栈;如果遇到‘(’,则将栈stk中操作符依次出栈并输出,直到‘)’为止,【注释:‘)’只出栈,不输出】;如果遇到运算符,则将栈stk中操作符依次出栈并输出,直到‘)’或者优先级小于当前操作符为止,然后将当前操作符压入栈stk中;
  3. 当扫描结束时,如果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;
}


代码写的有点乱,见谅!

最后,如文中出现错误,欢迎指正,痞子将及时修改,谢谢!

  • 11
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值