计算四则表达式(中缀式转后缀式,然后计算结果)

1. 目的:写一个程序,从键盘输入一个合法的四则运算表达式,输出计算结果;

2. 实现原理:将表达式先由中缀式转为后缀式,然后利用栈计算表达式结果;

3. 实现代码:

   版本1:

#include <iostream>
#include <stack> 
#include <string>
using namespace std;
const int SIZE = 100;

bool isOperator( char op )
{
	switch(op)
	{
		case '+':
		case '-':
		case '*':
		case '/':
			return true;
		default:
			return false;
	}
}

int priority( char op ) // 比较运算符优先级 
{
	int value = -1;
	switch(op)
	{
		case '#':
			value = -1;
			break;
		case '(':
			value = 0;
			break;
		case '+':
		case '-':
			value = 1;
			break;
		case '*':
		case '/':
			value = 2;
			break;
	}
	
	return value;
}

// 中缀式转换为后缀式 
// 把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格)  
int preToPostExp( string exp, char postExp[SIZE], int &len )
{
	stack<char> opSt; 
	opSt.push('#');
	int i = 0;
	int j = 0;
	
	while( exp[i] != '#' )
	{
		if( exp[i] >= '0' && exp[i] <= '9' || exp[i] == '.' )
		{
			postExp[j++] = exp[i];
			len++;
		} 
		else if( exp[i] == '(' )// 遇到“(”不用比较直接入栈
		{
			opSt.push(exp[i]);
		}
		else if( exp[i] == ')' )//遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式  
		{
			while( opSt.top() != '(' )
			{
				postExp[j++] = opSt.top();
				opSt.pop();
				len++;
			}
			opSt.pop(); //将'('出栈  将“(”出栈,后缀表达式中不含小括号 
		}
		else if( i == 0 && (exp[i] == '+' || exp[i] == '-')  ) //表明第一个数为正负号
		{
				postExp[j++] = exp[i];
				len++;
		} 	
		else if( isOperator(exp[i]) )
		{
			postExp[j++] = ' ';  //用空格隔开操作数
			len++;
			//当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程   
			while( priority(exp[i]) <= priority( opSt.top() ) )
			{
				postExp[j++] = opSt.top();
				opSt.pop();
				len++;
			}
			opSt.push(exp[i]); // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈 
		}
		i++;
	} 
	
	while( opSt.top() != '#' ) // 将所有的操作符加入后缀表达式
	{
		postExp[j++] = opSt.top();
		opSt.pop();
		len++;
	}
	
	return 0;
}

double read_number(char str[],int *i)  
{  
    double x=0.0;  
    int k = 0;  
    while(str[*i] >='0' && str[*i]<='9')  // 处理整数部分  
    {  
        x = x*10+(str[*i]-'0');  
        (*i)++;  
    }  
  
    if(str[*i]=='.') // 处理小数部分  
    {  
        (*i)++;  
        while(str[*i] >= '0'&&str[*i] <='9')  
        {  
            x = x * 10 + (str[*i]-'0');  
            (*i)++;  
            k++;  
        }  
    }  
    while(k!=0)  
    {  
        x /= 10.0;  
        k--;  
    }  
  
    return x;  
}  

// 计算后缀表达式结果 
double computePostExp( char post[SIZE] )
{
	stack<double> stack;   // 操作数栈 
	double x1 = 0;
	double x2 = 0;
	bool flag = false;
	int i = 0;
	double d = 0;
	
	while( post[i] != '\0' )
	{
		if( post[i] >= '0' && post[i] <= '9' )
		{
			d =  read_number(post,&i);
			if(flag) // 第一个数为负数
			{
				d = -d;
				flag = false;
			}
			stack.push(d);
		} 
		else if(post[i] == ' ' )
            i++;  
        else if (post[i] =='+')  
        {  
            x2 = stack.top();  
            stack.pop();
            x1 = stack.top(); 
			stack.pop();
            stack.push(x1+x2);  
            i++;  
        }  
        else if( post[i] == '-' && i == 0 ) //表明第一个数为负数,方便计算-1+2*3
        {
			flag = true;
			i++;
		}
        else if (post[i] =='-')  
        {  
            x2 = stack.top();  
            stack.pop();
            x1 = stack.top();
			stack.pop(); 
            stack.push(x1-x2);  
            i++;  
        }  
        else if (post[i] =='*')  
        {  
            x2 = stack.top();  
            stack.pop();
            x1 = stack.top();  
            stack.pop();
            stack.push(x1*x2);  
            i++;  
        }  
        else if (post[i] =='/')  
        {  
            x2 = stack.top();  
            stack.pop();
            x1 = stack.top();  
            stack.pop();
            stack.push(x1/x2);  
            i++;  
        }  
    }  
    
    return stack.top();	
}

int main()
{
	string exp = "";
	char postExp[SIZE];  // 保存后缀式结果 
	cout << "输入表达式(中缀,以#结束):"; 
	cin >> exp; // 以#号结束
	int len = 0;
	preToPostExp( exp, postExp, len );
	postExp[len] = '\0';
	cout << "后缀表达式为:";
	cout << postExp << endl;
	cout << "\n由后缀表达式计算出的数值结果:  "; 
	cout << computePostExp(postExp) << endl;
	
	system("pause");
	return 0;
} 
/*
中缀式变后缀式算法:
反复读取输入内容直到结束为止
如果是数字直接入栈
否则如果是'('就等待处理括号里面的
否则如果是')'就倒回来处理直到左括号为止的全部运算
否则就是普通运算符(+,-,*,/)
  反复看那些暂存的未处理的运算符,只要优先级不比本运算符低就处理(入栈)
  暂存本运算符
反复取出栈中的剩余运算符并保存,直到栈无运算符
*/

4. 结果:






转载地址:

http://blog.csdn.net/geekcoder/article/details/6829386

注:相对于转载的地址中的代码,改进之一就是能够计算第一个操作数为负数的情况,即计算类似:-1+2*3的表达式


版本2:

#include <iostream>
#include <stack>
#include <string>
using namespace std;

/*
表达式计算思路一:
1)准备两个栈:数据栈和运算符栈;
反复读取表达式:(2,3,4步)
2)如果是数,入数据栈;
3)如果是左括号,入运算符栈,如果是右括号,反复从运算符栈顶取运算符和
   从数据栈里取两个数据进行计算,并把结果入数据栈,直到遇到栈顶是左括号为止。
4)如果是运算符op,先跟栈顶的运算符比,只要不高于栈顶优先级,就取出栈顶
   的运算符和数据栈的两个数据进行计算,并把结果入数据栈,直到高于栈顶运算符优
   先级或者遇到左括号或者运算符栈空为止,此时把op入栈;
5)处理栈中的运算符:取出栈顶的运算符和数据栈的两个数据进行计算,并把结果入数据
   栈,直到运算符栈空为止;
6)这时数据栈中的数据就是计算结果。
*/ 
class Exp
{
	private:
		stack<char> ops;
		stack<double> ds;
		double v,  lh, rh; // 计算结果和临时操作数变量 
		char op; //运算符 
	public:
		double calinput()//读取并计算表达式直到结束为止
		{
			do
			{
				readdata();
				skipspace(); //跳过空白 
			}
			while( readop() );
			calremain(); //处理栈中剩余的运算符
			return v; 
		} 
		
		void readdata() //在该出现数据的时候可能出现'(' 
		{
			// 如1+((2*3)) 左括号可能是多个 
			while( !(cin>>v) )  //读取数据失败,此时读取应该是'(',而v为double类型 
			{
				cin.clear();
				cin >> op; //读取'('
				if( op != '(' )
				{
					throw string("在该出现数值的地方出现了") + op; 
				} 
				ops.push(op); //左括号入栈 
			}
			ds.push(v);
			return;
		}
		void skipspace()
		{
			while( cin.peek() == ' ' || cin.peek() == '\t' ) //cin.peek只看不取走
			{
				cin.ignore(); //丢掉一个空白字符 
			} 
		}
		
		bool readop() //读取运算符,可能出现右括号或者换行符(表达式结束) 
		{
			//如(2*(3+4/(4-5))),右括号可能是多个 
			 while( (op = cin.get() ) == ')' )
			 {
				while( ops.top() != '(' )
				{
					rh = ds.top(); //取左操作数 
					ds.pop(); 
					lh = ds.top();//取右操作数 
					ds.pop();
					ds.push( cal( lh, ops.top(), rh ) ); //计算并入栈
					ops.pop(); //取走运算符 
				}	
				ops.pop(); //丢弃'(' 
             }
             if( op == '\n' )
             {
				return false;
			 }
			 
             if( strchr("+-*/", op ) == NULL ) //无效运算符 
             {
				throw string("无效运算符") + op; 
			 }
			 while( !ops.empty() && ops.top() != '(' && !prior( op, ops.top() ) )
			 {
				rh = ds.top(); ds.pop();
				lh = ds.top(); ds.pop();
				ds.push( cal( lh, ops.top(), rh ) ); //计算并入栈
				ops.pop(); //取走运算符 	
			 }
			 
			 ops.push(op);
			 return true;
		} 
		
		void calremain()
		{
			while( !ops.empty() )
			{
				rh = ds.top(); ds.pop();
				lh = ds.top(); ds.pop();
				ds.push( cal( lh, ops.top(), rh ) ); //计算并入栈
				ops.pop(); //取走运算符 
			}
			if( ds.size() != 1 )
			{
				throw string("无效的表达式"); 
			}
			v = ds.top();
			ds.pop();
			return;
		}
		double cal( double lh, char op, double rh )
		{
			return op == '+'?lh+rh:op=='-'?lh-rh:op=='*'?lh*rh:lh/rh;
		}
		
		bool prior( char o1, char o2 )//若o1比o2优先级高返回true,否则返回false 
		{
			return o1 != '+' && o1 != '-' && o2 != '*' && o2 != '/';
		}
		
};

int main()
{
	Exp e;
	try
	{
		cout << e.calinput() << endl;
	}
	catch( const string &e )
	{
		cout << e << endl;
	}
	
	system("pause");
	return 0;
} 
输出结果:



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值