• 后缀表达式(逆波兰式)学习记录


    在本周作业中遇到了后缀表达式(逆波兰式)。一是将一般的中缀表达式转化为后缀表达式;二是后缀表达式的值的计算。

    这两题我都用的是数组模拟栈来解决,查阅资料并不多,百度百科:逆波兰式 中的逆波兰式的概念、实现、举例我觉得都比csdn、博客园上的帖子详细而且好理解,所以主要是参考了百度百科。

    题一:将中缀表达式转化为后缀表达式

    所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右进行(不用考虑运算符的优先级)。

    如:中缀表达式 3(5–2)+7 对应的后缀表达式为:352-7+ 。

    请将给出的中缀表达式转化为后缀表达式并输出。

    输入格式:

    输入仅一行为中缀表达式,式中所有数字均为个位数,表达式长度小于1000。

    输出格式:

    输出一行,为后缀表达式,式中无空格。

    输入样例:

    2+4*8+(8 * 8+1)/3

    输出样例:

    248*+88 * 1+3/+

    一般算法:
    首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆波兰式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,即s1[0]='#'。从中缀式的左端开始取字符,逐序进行如下步骤:
    (1)若取出的字符是操作数,则分析出完整的运算数(数字),该操作数直接送入S2栈。本题的要求较为简单,题面说数字只有个位数,所以不存在10以上的数字。
    (2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级(不包括括号运算符)大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,最后将该运算符送入S1栈。
    (3)若取出的字符是“(”,则直接送入S1栈顶。
    (4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
    (5)重复上面的1~4步,直至处理完所有的输入字符
    (6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
    (7)从0到S2的栈依次输出S2的字符,即为答案。

    编写一个判断字符优先级的函数:

    int oplevel(char op)
    {
    	if(op=='*'||op=='/')return 3;
    	if(op=='+'||op=='-')return 2;
    	if(op=='(')return 1;
    	if(op=='#')return 0;
    }
    

    本题除了加减乘除外还有涉及到左括号( 的判断和最低级的 # 的判断。

    读入、处理:

    	s1[0]='#';
    	string str;
    	int cur1=1,cur2=0;//两个栈的栈顶
    	cin>>str;
    

    之后op=str[i],再进行如下处理:
    如果op是数字,压入S2,如果是左括号,直接压入S1:

    		if(op>='0'&&op<='9')s2[cur2++]=op;
    		if(op=='(')s1[cur1++]=op;
    

    遇到右括号):

    		if(op==')')
    		{
    			while(1)
    			{
    				if(s1[cur1-1]=='('){
    					s1[cur1-1]=0;
    					cur1--;
    					break;
    				}
    				s2[cur2++]=s1[cur1-1];
    				cur1--;
    			}
    		}
    

    如果是加减乘除的话:

    		if(op=='+'||op=='-'||op=='*'||op=='/')
    		{		
    			while(1)
    			{
    				if(oplevel(s1[cur1-1])<oplevel(op))    //如果当前S1的栈顶比op的优先级低,则将op压入S1
    				{	
    					s1[cur1++]=op;
    					break;
    				}
    				else                                  
         //否则不断将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)op的优先级,最后将op送入S1栈
    				{
    					s2[cur2++]=s1[cur1-1];
    					s1[cur1-1]=0;
    					cur1--;
    				}
    			}			
    		}
    

    最后将S1中剩下的元素压入S2:

    	for(int i=cur1-1;i>0;i--)s2[cur2++]=s1[i];
    

    输出答案:

    	for(int i=0;i<cur2;i++)cout<<s2[i];
    

    题二:计算后缀表达式的值

    Kunkun学长觉得应该让学弟学妹了解一下这个知识点:后缀表达式相对于中缀表达式更容易让计算机理解和学习。现在kunkun学长给出一串后缀表达式,你能帮他算出这个后缀表达式的值吗?

    输入格式:

    第一行输入后缀表达式长度n(1<=n<=25000);

    第二行输入一个字符串表示后缀表达式(每个数据或者符号之间用逗号隔开,保证输入的后缀表达式合法,每个数包括中间结果保证不超过long long长整型范围)

    输出格式:

    输出一个整数,即后缀表达式的值。

    输入样例1:

    6
    10,2,+

    输出样例1:

    12

    输入样例2:

    14
    2,10,2,+,6,/,-

    输出样例2:

    0

    一般算法:
    首先需要建立一个栈stk用来储存数值和用于计算。从后缀表达式的左端开始取字符:
    (1)若取出的字符是数字,则分析出完整的数字后放入栈顶。
    (2)若取出的字符是加减乘除就对栈顶下一个数stk[cur-2]与栈顶stk[cur-1]做运算,将结果赋值给stk[cur-2],并将栈顶减一。
    (3)分析完所有字符后,输出栈底stk[0],即为答案。

    定义以及处理:

        long long stk[100000];//全局变量
    

    其他变量:

    	long long n,now=0,cur=0;
    	string s;
    	char op,last;
    	bool nega=false;//negative 负数 
    	cin>>n>>s;
    

    判断输入的数字是否为负数:

    		if(op=='-'&&s[i+1]>='0'&&s[i+1]<='9')//当前是负号 - 且下一个字符是数字,则这个输入的是负数而不是减号 
    		{
    			nega=true;
    			continue;
    		}
    

    提取数字:

    		if(op==','&&s[i-1]>='0'&&s[i-1]<='9')//如果逗号前是数字 
    		{		
    			if(nega){
    				now*=-1;
    				nega=false;
    				}
    			stk[cur++]=now;
    			now=0;	
    		}	
    

    遇到加减乘除,做运算。

    这步是该题的重点!!要搞清楚cur所指向的是栈顶元素的上面一格,另外在减 和 除 运算中,栈顶元素下面一格stk[cur-2]为被减数和被除数,需要注意。同时要赋值给的是stk[cur-2]。

    		if(op=='+'||op=='-'||op=='*'||op=='/')
    		{
    			long long a=stk[cur-1],b=stk[cur-2];
    			if(op=='+')stk[cur-2]=b+a;
    			if(op=='-')stk[cur-2]=b-a;//注意是谁减谁
    			if(op=='*')stk[cur-2]=b*a;
    			if(op=='/')stk[cur-2]=b/a;//谁除谁
    			cur--;
    		}
    

    最后输出栈底即为答案。

  • 相关阅读:
    Go
    go-反射
    go-map
    go中数组与切片
    goroutine 和 channel
    Go中的闭包
    新版 C# 高效率编程指南
    gitignore 规则和不起作用的解决方案
    Linux系统部署.Net Core3.1项目
    List<对象> 根据某个字段提出一个 List<String>,并且去重
  • 原文地址:https://www.cnblogs.com/LiangYC1021/p/12583968.html
Copyright © 2020-2023  润新知