表达式二叉树

总结了一下常见的表达式求值问题,写了一个模板,输入为中缀式时,用中缀式建立表达式二叉树,可以打印前缀式和后缀式,可以用前缀式计算,也可以用后缀式计算。


代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<vector>
#include<climits>
#include<ctime>
#include<stack>
#include<algorithm>
using namespace std;

#define MAX 1005
#define CLR(arr, what) memset(arr, what, sizeof(arr))

struct Node
{
	char ope[10];
	Node *lchild, *rchild;
	Node()
	{
		CLR(ope, '\0');
		lchild = rchild = NULL;
	}
};

class Exp
{
private:
	Node *root;
	int prelen, postlen; //前缀式长度、后缀式长度
	int pos; //前缀式计算指针
	char str[MAX], pre[MAX], post[MAX]; //中缀式、前缀式、后缀式
	stack<double> num; //后缀式计算->数字栈
	double answer;

public:
	Exp(char[]); //构造函数
	Node* Build_Exp(int start, int end); //建表达式树

	void Pre_Order(Node*); //前缀式遍历
	void Post_Order(Node*); //后缀式遍历

	void PreOut(){cout<<pre<<"="<<endl;} //输出前缀式
	void PostOut(){cout<<post<<"="<<endl;} //输出后缀式

	double Pre_Calucate(); //前缀式计算
	double Post_Calucate(); //后缀式计算

	double result(); //输出结果

	void clear(Node*);
	~Exp(){	clear(root);}; //销毁二叉树
};

Exp::Exp(char s[])
{
	root = new Node;
	pos = -1;
	prelen = 0, postlen = 0;
	CLR(str, '\0'); CLR(pre, '\0'), CLR(post, '\0');
	while(!num.empty())
		num.pop();
	strcpy(str, s);
	root = Build_Exp(0, strlen(str) - 2); //中缀式长度可按题目改变~
}

Node* Exp::Build_Exp(int src, int des)
{
	if(src > des)
		return 0;
	if(str[src] >= '0' && str[src] <= '9' || str[src] == '.')
	{
		double temp;
		int length;
		sscanf(&str[src], "%lf%n", &temp, &length);
		if(src + length -1 == des)
		{
			Node* cur = new Node;
			sprintf(cur->ope, "%lf", temp);
			cur->ope[length] = '\0';
			cur->lchild = NULL, cur->rchild = NULL;
			return cur;
		}
	}
	int optr1 = -1, optr2 = -1, pos = 0; // +- || ×/
	for(int i = src; i <= des; ++i) //寻找树根
	{
		switch(str[i])
		{
		case '(': pos++; break;
		case ')': pos--; break;
		case '+': 
		case '-': if(pos == 0) optr1 = i; break;
		case '*':
		case '/': if(pos == 0) optr2 = i; break;
		}
	}
	if(optr1 < 0)
		optr1 = optr2;
	if(optr1 < 0)
		return Build_Exp(src + 1, des - 1); //被括号包围
	Node* upper = new Node;
	upper->ope[0] = str[optr1];
	upper->ope[1] = '\0';
	upper->lchild = Build_Exp(src, optr1 - 1); //递归建左子树
	upper->rchild = Build_Exp(optr1 + 1, des); //递归建右子树
	return upper;
}

void Exp::Pre_Order(Node* rot)
{
	if(rot != NULL)
	{
		sprintf(&pre[prelen], "%s", rot->ope);
		prelen += strlen(rot->ope);
		pre[prelen++] = ' ';
		Pre_Order(rot->lchild);
		Pre_Order(rot->rchild);
	}
}

void Exp::Post_Order(Node* rot)
{
	if(rot != NULL)
	{
		Post_Order(rot->lchild);
		Post_Order(rot->rchild);
		sprintf(&post[postlen], "%s", rot->ope);
		postlen += strlen(rot->ope);
		post[postlen++] = ' ';
	}
}

double Exp::Pre_Calucate()
{
	pos++;
	if(pre[pos] == ' ') pos++;
	if(pre[pos] >= '0' && pre[pos] <= '9')
	{
		double temp;
		int length;
		sscanf(&pre[pos], "%lf%n", &temp, &length);
		pos += length - 1;
		return temp;
	}
	if(pre[pos] == '+')
		return Pre_Calucate() + Pre_Calucate();
	if(pre[pos] == '-')
		return Pre_Calucate() - Pre_Calucate();
	if(pre[pos] == '*')
		return Pre_Calucate() * Pre_Calucate();
	if(pre[pos] == '/')
		return Pre_Calucate() / Pre_Calucate();
}

double Exp::Post_Calucate()
{
	postlen = strlen(post) - 1; //最后一个是空格
	for(int i = 0; i < postlen; ++i)
	{
		if(post[i] >= '0' && post[i] <= '9') //操作数
		{
			double temp;
			int length;
			sscanf(&post[i], "%lf%n", &temp, &length);
			i += length - 1;
			num.push(temp);
		}
		else if(post[i] == ' ')
			continue;
		else//操作符
		{
			double a, b;
			b = num.top(); num.pop();
			a = num.top(); num.pop();
			switch(post[i])
			{
			case '+': num.push(a + b); break;
			case '-': num.push(a - b); break;
			case '*': num.push(a * b); break;
			case '/': num.push(a / b); break;
			}
		}
	}
	return num.top();
}

double Exp::result()
{
	Pre_Order(root);
	PreOut();
	Post_Order(root);
	PostOut();
	return Pre_Calucate();
	//return Post_Calucate();
}

void Exp::clear(Node* rot)
{
	if(rot->lchild != NULL)
		clear(rot->lchild);
	if(rot->rchild != NULL)
		clear(rot->rchild);
	delete(rot);
}

int main()
{
	int ncase;
	scanf("%d", &ncase);
	while(ncase--)
	{
		char s[MAX];
		cin>>s;
		Exp e(s);
		printf("%.2lf\n", e.result());
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值