数据结构:四则运算

1.平时我们所接触到的四则运算都是中序表达式,而要进行编程计算时要考虑符号优先级神马的很麻烦,故通常将其转换为前序表达式或者后序表达式:

  1. 中序表达式:2*3/(2-1)+3*(4-1)
  2. 前序表达式:+/*23-21*3-41
  3. 后序表达式:23*21-/341-*+

2.中序转前序:

1.将中序表达式逆转: )1-4(*3+)1-2(/3*2

2.处理逆转后的字符串:

1.如果是操作数,直接输出;

2.如果是运算符

1.如果是“)”,直接入栈;

2.如果是“(”,连续出栈,直至遇到“(”;

3.如果既不是“)”,也是不是“(”

1.栈空,则入栈;

2.栈顶为“)”,则入栈;

3.如果此时符号优先级>=栈顶元素优先级,则入栈;否则出栈,直到栈中的符号优先级大于此时符号或者栈为空;

3.处理完字符串后,如果栈不为空,将栈中的符号输出;   //14-3*12-32*/+

4.然后将字符从左到右遍历,不断的将离符号最近的两个数进行进行运算(比如:912-),直到结尾;(按理论是将该字符串逆转变成前序表达式,然后在从右到左进行处理,后序表达式是从左到右进行处理);


3.程序如下:

我选取的存放前序表达式的数据结构为vector<vector<char> >,主要是为了装某个大于一位数值(比如:562),感觉太麻烦了,欢迎大家批评指正;


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

int StringInt(string &a)
{
	return atoi(a.c_str());
}

double CharInt(vector<char> &vec)
{
	vector<char>::iterator iter=vec.begin();
	double result=0;
	for( ; iter!=vec.end(); iter++)
		result = result*10 + (*iter-'0');

	return result;
}

//1.反转表达式
void Reserve(char *p)
{
	if(p==NULL)
		return ;
	char *q=p;
	while(*q!='\0')
		q++;
	q--;
	while(p<q)
	{
		char temp = *p;
		*p=*q;
		*q=temp;
		p++;q--;
	}
}
//2.创建符号优先级
int Getprior(char k)
{
	int prior=-1;
	switch(k)
	{
	case '+':
		prior=1;
		break;
	case '-':
		prior=1;
		break;
	case '*':
		prior=2;
		break;
	case '/':
		prior=2;
		break;
	case '(':
		prior=0;
		break;
	case ')':
		prior=3;
		break;
	default:
		prior=-1;
		break;
	}
	return prior;
}
//用于计算
double Calculate(int a, int b, char k)
{
	double prior=0;
	switch(k)
	{
	case '+':
		prior=a+b;
		break;
	case '-':
		prior=a-b;
		break;
	case '*':
		prior=a*b;
		break;
	case '/':
		prior=(double)a/(double)b;
		break;
	default:
		break;
	}
	return prior;
}
//3.用一个栈来处理符号
bool Getresult(char *p, vector<vector<char> > &vec1)   //之所以是一个vector<vector<char> >的数组而不是char,是为了防止某数超出char的范围
{
	if(p==NULL)
		return false;
	vector<char> vec11;
	stack<char> sta1;   //临时存放符号
	while(*p!='\0')
	{
		if(*p==')')
			sta1.push(*p++);
		else if(*p=='(')
		{
			vec11.clear();
			while(sta1.top()!=')')
			{
				vec11.push_back(sta1.top());
				vec1.push_back(vec11);
				sta1.pop();
			}
			sta1.pop();  //删除')'
			p++;
		}
		else if(*p<='9' && *p>='0')  //表示数字
		{
			vec11.clear();
			while(*p<='9' && *p>='0' && *p!='\0')
			{
				vec11.push_back(*p++);
			}
			vec1.push_back(vec11);
		}
		else if(*p!='(' && *p!=')')  //表示其他符号
		{
			if(sta1.empty())
				sta1.push(*p++);
			else if(sta1.top()==')')
				sta1.push(*p++);
			else if(Getprior(sta1.top())==Getprior(*p) || Getprior(*p)>=Getprior(sta1.top()))
				sta1.push(*p++);
			else if(Getprior(Getprior(*p)<sta1.top()))
			{
				vec11.clear();
				while(!sta1.empty() && (Getprior(*p)<Getprior(sta1.top())))   //易错点2:栈有可能已经空了,并且需要放到前面
				{
					vec11.push_back(sta1.top());
					vec1.push_back(vec11);
					sta1.pop();
				}
				sta1.push(*p++);
			}
		}
		else
			return false;
	}
	while(!sta1.empty())  //易错点3:容易丢掉后面在栈里的东西
	{
		vec11.clear();
		vec11.push_back(sta1.top());
		vec1.push_back(vec11);
		sta1.pop();
	}
	//output(vec1);
	return true;
}
//4.反转成前序表达式+从右到左遍历=直接从左到右
double Calculate(vector<vector<char> > &vec1)
{
	int i=0;
	vector<vector<char> >::iterator iterRow=vec1.begin();
	double a[50]={0.0};
	for( ; iterRow!=vec1.end(); iterRow++)
	{
		vector<char>::iterator iterCol=iterRow->begin();
		if(*iterCol=='+' || *iterCol=='-' || *iterCol=='*' || *iterCol=='/')
		{
			if(i==2)
			{
				a[0] = Calculate(a[1],a[0],*iterCol);   //注意:先出来的那个是被减数 two-one
				i=1;
			}
			else if(i>2)    //表示三个数以上连续一个符号的情况,易错点
			{
				a[i-2] = Calculate(a[i-1],a[i-2],*iterCol);   
				i=i-1;
			}
		}
		else
		{
			a[i++] = CharInt(*iterRow);
		}

	}

	return a[0];
}
void Calculate()  //测试
{
	char str[]={"2*3/(2-1)+3*(4-1)"};
	vector<vector<char> > vec1;
	Reserve(str);
	Getresult(str, vec1);
	double result = Calculate(vec1);
	cout<<result<<endl;
}

int main()
{
<span style="white-space:pre">	</span>Calculate();
    return 0;
}


参考文献:http://www.cnblogs.com/hsrzyn/archive/2009/12/21/1629274.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值