调度场算法与逆波兰表达式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ACdreamers/article/details/46431285

本文的主要内容是如何求一个给定的表达式的值,具体思路就是先将普通算术的中缀表达式转化为后缀表达式,这一步用到的算法叫做调度场算法。然后对后缀表达式,也就是逆波兰表达式求值。




题目:http://acm.hdu.edu.cn/showproblem.php?pid=3596


代码:(参考别人的重构)

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stack>
#include <map>

#define N   10005
#define EPS 1e-9 

using namespace std;

struct Node
{
	double val;
	char   opt;
	Node(double val = 0, char opt = ' ')
	{
		this->val = val;
		this->opt = opt;
	}
};

Node node[N];
char str[N];
map<char, int> mp;

void Init()
{
	mp['('] = 0;
	mp['-'] = mp['+'] = 1;
	mp['*'] = mp['/'] = 2;
	mp['^'] = 3;
}

//逆波兰表达式的计算
double CalPoland(Node node[], int n)
{
	stack<double> s;
	for(int i = 0; i < n; i++)
	{
		if(node[i].opt == ' ')
			s.push(node[i].val);
		else
		{
			double a = s.top();
			s.pop();
			double b = s.top();
			s.pop();
			switch(node[i].opt)
			{
				case '+':
					s.push(b + a);
					break;
				case '-':
					s.push(b - a);
					break;
				case '*':
					s.push(b * a);
					break;
				case '/':
					if(fabs(a) < EPS)
						throw true;
					s.push(b / a);
					break;
				case '^':
					s.push(pow(b, a));
					break;
			}
		}
	}
	return s.top();
}

//调度场算法
double ShuntYardAlgo(char str[])
{
	stack<char> oper;

	//inNum标记当前是否可以输入数字
	bool inNum = true;
	//hasDot标记是否已经输入小数点
	bool hasDot = true;
	
	int p = 0;    //扫描指针位置
	int cnt = 0;  //符号或者数字计数器
	int sign = 1; //表示正负符号

	while(str[p])
	{
		if(isdigit(str[p]) || str[p] == '.')
		{
			if(inNum)
			{
				double val = 0;
				double w = 1;
				if(str[p] == '.')
				{
					hasDot = true;
					val = 0;
				}
				else
				{
					hasDot = false;
					val = str[p] - '0';
				}
				p++;
				while(isdigit(str[p]) || str[p] == '.')
				{
					if(str[p] == '.')
					{
						if(hasDot) throw true;
						hasDot = true;
					}
					else
					{
						if(hasDot)
						{
							w *= 0.1;
							val += (str[p] - '0') * w;
						}
						else
							val = val * 10 + str[p] - '0';
					}
					p++;
				}
				p--;
				node[cnt++] = Node(val * sign, ' ');
				sign = 1;
				inNum = false;
			}
			else throw true;
		}
		else
		{
			switch(str[p])
			{
				case '(':
					oper.push(str[p]);
					break;
				case ')':
					while(!oper.empty() && oper.top() != '(')
					{
						node[cnt++] = Node(0, oper.top());
						oper.pop();
					}
					if(oper.empty())
						throw true;
					oper.pop();
					break;
				case '+':
				case '-':
				case '*':
				case '/':
				case '^':
					if(inNum)
					{
						if(str[p] != '+' && str[p] != '-') 
							throw true;
						while(str[p] == '+' || str[p] == '-')
						{
							if(str[p] == '-') 
								sign *= -1;
							p++;
						}
						p--;
					}
					else
					{
						while(!oper.empty() && mp[str[p]] <= mp[oper.top()])
						{
							node[cnt++] = Node(0, oper.top());
							oper.pop();
						}
						oper.push(str[p]);
						inNum = true;
					}
					break;
			}
		}
		p++;
	}
	while(!oper.empty())
	{
		node[cnt++] = Node(0, oper.top());
		oper.pop();
	}
	return CalPoland(node, cnt);
}

int main()
{
	Init();
	while(scanf("%s", str) != EOF)
	{
		try{
			printf("%.8lf\n", ShuntYardAlgo(str));
		}
		catch(bool){
			puts("The teacher is so lazy!");
		}
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/ACdreamers/article/details/46431285