• 使用逆波兰式进行表达式求值


    中缀表达式及后缀表达式图解中说明了使用逆波兰式进行表达式求值的方法。这里使用C++进行实现。实现和原理解说有一点不同,须要进一步进行细化。

    关于将中缀表达式转换成后后缀表达式的规则:

    规则:从左到右遍历中缀表达式的每一个数字和符号,若是数字就输出。即成为后缀表达式的一部分;若是符号。则推断其与栈顶符号的优先级。是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈,一直到终于输出后缀表达式为止。

    上面的规则转换成以下的运行规则:

    1.遇到操作数:直接输出(加入到后缀表达式中)
    2.栈为空时,遇到运算符。直接入栈
    3.遇到左括号:将其入栈
    4.遇到右括号:运行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号。左括号不输出。
    5.遇到其它运算符:加减乘除:弹出全部优先级大于或者等于该运算符的栈顶元素。然后将该运算符入栈
    6.终于将栈中的元素依次出栈,输出。

    须要在流程中对上面6种情况下进行推断并作对应的处理。而且因为数字可能有多位,所以对操作数的取值也是一个问题。


    //比較lhs的优先级是否不高于rhs。rhs表示栈顶的符号
    bool priority(char lhs,char rhs)
    {
    		if (rhs=='(')
    			return false;
    		if (lhs=='+'||lhs=='-')
    			return true;
    		if ((lhs=='*'||lhs=='/')&&(rhs=='*'||rhs=='/'))
    			return true;
    		return false;
    }
    
    //将中缀表达式转换成后缀式
    string inPrefix2postPrefix(string str)
    {
    	string res;//后缀表达式结果
    	stack<char> s;
    	for (int i=0;i<str.size();i++)
    	{
    		//假设是数字,直接增加后缀表达式结果中
    		if (isdigit(str[i]))
    		{
    			while (i<str.size()&&isdigit(str[i]))
    			{
    					res+=str[i];
    					i++;
    			}
    			i--;//注意这里要将i减1。由于上面的循环将i多右移了一位。假设不减1,会漏掉一位
    			res+=" ";
    		}
    		else //假设是符号,须要与栈顶的元素进行比較
    		{
    			 //假设栈为空。将其直接压入栈中;假设是左括号(。也直接将其压入栈中
    				if (s.empty()||str[i]=='(')
    						s.push(str[i]);
    				else
    				{
    						//当碰到右括号时。将栈中的数据出栈,直到碰到左括号。注意左右括号都不须要增加结果res中
    						if (str[i]==')')
    						{
    								while (!s.empty()&&s.top()!='(')//注意在对栈运行top操作之前须要推断栈是否为空
    								{
    									res+=s.top();
    									res+=" ";
    									s.pop();
    								}
    								s.pop();
    						}
    						else  
    						{
    								//此时表示该字符为符号,而且不为'('和')'
    								if (priority(str[i],s.top()))//假设它的优先级不高于栈顶符号,那么将栈顶符号出栈
    								{
    										while(!s.empty()&&priority(str[i],s.top()))
    										{
    												res+=s.top();
    												res+=" ";
    												s.pop();
    										}
    										s.push(str[i]);//最后记得将该符号入栈
    								}
    								else //假设它的优先级比栈顶符号高,那么直接入栈
    										s.push(str[i]);
    						}
    				}
    		}
    	}
    	while(!s.empty())//遍历完字符串后将栈中剩余的元素增加结果集中
    	{
    		res+=s.top();
    		res+=" ";
    		s.pop();
    	}
    	return res;
    }



    上面是将中缀表达式转换成后缀表达的方法,接下来是处理后缀表达式的方法:

    • 规则:从左到右遍历表达式的每一个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈。一直到终于获得结果。
    须要注意从栈顶弹出的第一个元素是第一个操作数,弹出的第二个元素是第二个操作数,不要把顺序弄反了。此时栈用来进出运算的数字。

    int operate(int first,int second,char op)
    {
    	int res=0;
    	switch (op)
    	{
    		case '+':
    			res= first+second;
    			break;
    		case '-':
    			res=first-second;
    			break;
    		case '*':
    			res=first*second;
    			break;
    		case '/':
    			res=first/second;
    			break;
    		default:
    			break;		
    	}
    	return res;
    }
    int   calculateByPostPrefix(string input)
    {
    	stack<int> s;
    	int tmp=0;
    	for (int i=0;i<input.size();i++)
    	{
    		if (isdigit(input[i]))//假设遇到的是数字。就将数字入栈
    		{
    			while(i<input.size()&&isdigit(input[i]))
    			{
    				tmp=10*tmp+input[i]-'0';
    				i++;
    			}
    			//得到数字以后将这个输入压入栈中
    			s.push(tmp);
    			i--;
    		}
    		else if(input[i]==' ')//假设遇到空格,就将tmp重置为0
    			tmp=0;
    		else//此时遇到的就是符号
    		{
    			   //取出两个操作数。并进行计算
    				int second=s.top();
    				s.pop();
    				int first=s.top();
    				s.pop();
    				int local=operate(first,second,input[i]);
    				s.push(local);
    		}
    	}
    	return s.empty()?0:s.top();
    }


    主函数例如以下:

    int main()
    {
    	string str;//9+(3-1)*3+10/2
    	cout<<"请输入合法的表达式(支持整数的+,-,*,/,括号运算):"<<endl;
    	while(getline(cin,str))
    	{
    		string ot=inPrefix2postPrefix(str);
    		cout<<"后缀表达式为:"<<ot<<endl;
    		cout<<"计算结果为:"<<calculateByPostPrefix(ot)<<endl;
    		cout<<"请输入表达式:"<<endl;
    	}
    	system("pause");
    	return 0;
    }

    取前一篇文章中的样例“9+(3-1)*3+10/2”进行測试,查看转换后的后缀表达式以及运算结果,程序支持在控制台中持续输入几组数据并计算结果。


    完整的代码:下载

  • 相关阅读:
    vim内外部鼠标复制 粘贴
    nginx 问题解决nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    Installation of the latest version of netease-cloud-music on Fedora 30 linux platform
    Linux就该这么学11学习笔记
    Linux就该这么学10学习笔记
    css day2
    Linux就该这么学09学习笔记
    Linux就该这么学08学习笔记
    css day1
    Linux就该这么学07学习笔记
  • 原文地址:https://www.cnblogs.com/llguanli/p/7133082.html
Copyright © 2020-2023  润新知