您的位置:首页 > 其它

机试算法讲解: 第14题 实现一个简单计算器

2015-07-31 00:04 501 查看
/*
问题:简单的计算器,读入只含 +,-,*,/的非负整数计算式,计算表达式的值
输入:
若干测试用例,每个测试用例占1行,每行<=200个字符,整数和字符之间用一个空格分隔。无非法表达式。遇只含有0的一行时,结束输出
输出:
输出1行该表达式的值,保留2位小数

输入:
(1 + 2)                     1 2 +
(4 + 2 * 5 - 7 / 11)         4 2 5 * + 7 11 / -
0

输出:
3.00
13.36

思路:用栈,后缀表达式,首先*和/的优先级较高,碰到需要优先处理,其实就是中缀表达式转换为后缀表达式,然后每次栈顶为运算符时,
取栈顶元素A,和次栈顶元素B,计算 B 运算符 A 即可,得到的计算结果再存入栈
问题转化为:中缀转后缀
好像是从右向左扫描
7 / 11 ->

关键:
1设定数字栈和运算符栈,
遇到数字直接压入数字栈中
遇到运算符,{若当前运算符#比栈顶运算符优先级小 或者 栈为空,则压入当前运算符
            {否则,从数字栈中弹出栈顶元素A,次栈顶元素B,计算 B # A,将计算后的结果压入数字栈中
需要为该表达式设定运算符(和),两者的优先级最低,表示表达式的开始与结束
循环终止条件:运算符栈中仅剩2个运算符,并且栈顶运算符为")"时,比较优先级应该循环比较

2由于字符串中有空格,而scanf回跳过不处理,认为是下一次输出,因此对于含有空格或制表符的字符串用gets函数,而不是scanf
char* gets(char* str);

3打印2位小数用printf("%.2f",i);不是%.2d,这表示整数
%n,mf:即输出总共n位,其中有m位小数,-号是右端补空格

4易错:11看成了2个1,应该以空格为分隔符(截取的字符串),来判定数字
*/

#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <string.h>
#include <map>

using namespace std;

bool isNumber(char c)
{
	if(' '==c)
	{
		return false;
	}
	char sNum[11] = {'0','1','2','3','4','5','6','7','8','9'};
	int i = 0;
	while('\0'!=sNum[i])
	{
		//if(c=sNum[i])//关键是==而不是=
		if(c==sNum[i])
		{
			return true;
		}
		i++;
	}
	return false;
}

bool isOperator(char c)
{
	if(' '==c)
	{
		return false;
	}
	char sOpe[7] = {'(',')','+','-','*','/'};
	int i = 0;
	while('\0'!=sOpe[i])
	{
		//if(c=sOpe[i])
		if(c==sOpe[i])
		{
			return true;
		}
		i++;
	}
	return false;
}

int my_atoi(char c)
{
	switch(c)
	{
	case '0':return 0;
	case '1':return 1;
	case '2':return 2;
	case '3':return 3;
	case '4':return 4;
	case '5':return 5;
	case '6':return 6;
	case '7':return 7;
	case '8':return 8;
	case '9':return 9;
	default:
		return -999;
	}
	return -999;
}

int main(int argc,char* argv[])
{
	//设定优先级,+-一样,()一样,/*一样
	map<char,int> mMap;
	mMap.insert(make_pair<char,int>('(',1));
	mMap.insert(make_pair<char,int>(')',1));
	mMap.insert(make_pair<char,int>('+',2));
	mMap.insert(make_pair<char,int>('-',2));
	mMap.insert(make_pair<char,int>('*',3));
	mMap.insert(make_pair<char,int>('/',3));
	char sInput[201];
	//关键是1有空格,计算机就认为你重新输入了,必须扣除这种情况
	//while(EOF!=scanf("%s",sInput))
	while(gets(sInput))
	{
		stack<char> stackOpe;//运算符栈
		//为其添加开始标记(
        stackOpe.push('(');
		//stack<int> stackNum;//运算数栈
		//易错,由于保留两位小数,数字栈的类型为double
		stack<double> stackNum;
		int i = 0;
		//必须在最后给其添加')' 
		while('\0'!=sInput[i])
		{
			/*如果运算符栈只剩2个元素,并且栈顶为,')',也退出循环
			if(2==stackOpe.size() && ')'==stackOpe.top())
			{
				break;
			}
			*/
			bool isNumbe = false;
			bool isOp = false;
			if(' '==sInput[i])
			{
				i++;
				continue;
			}
			//获取连续的数字
			int retn = 0;
			if(sInput[i] >= '0' && sInput[i] <= '9')
			{
				while(sInput[i] >= '0' && sInput[i] <= '9')
				{
					retn *= 10;
					retn += sInput[i] - '0';
					isNumbe = true;
					i++;
				}
				i--;//确保拿到的是数字
			}
			//其余默认为运算符
			else
			{
				isOp = true;
			}
			//数字进数字栈
			if(isNumbe || isNumber(sInput[i]))
			{
				//stackNum.push(my_atoi(sInput[i]));
				//stackNum.push(my_atoi(retn));
				stackNum.push(retn);
				i++;
				//如果这是最后一个数字,则在运算符栈中添加')'
				if('\0'==sInput[i])
				{
					sInput[i] = ')';
					sInput[i+1] = '\0';
				}
			}
			//运算符进运算符栈
			else if(isOp || isOperator(sInput[i]))
			{
				//如果栈空,直接压入该运算符
				if(stackOpe.empty())
				{
					stackOpe.push(sInput[i]);
					i++;//计数器累加
				}
				else
				{
					//如果当前运算符的优先级比栈顶运算符的优先级要高,则进栈,相同优先级不进栈
					map<char,int>::iterator itFind = mMap.find(sInput[i]);
					if(itFind->second > (mMap.find(stackOpe.top()))->second)
					{
						stackOpe.push(sInput[i]);
						i++;
					}
					//如果是栈顶优先级高 >= 当前运算符优先级,则弹出栈顶元素和次栈顶元素,计算结果 1 + 2全部输入完成后,它没有计算,因此需要给定最低的两个运算符
					else
					{
						double iBackNum = stackNum.top();
						stackNum.pop();
						double iFrontNum = stackNum.top();
						stackNum.pop();
						double iRes = 0.0;
						switch(stackOpe.top())
						{
						case '+':
							iRes = (iFrontNum + iBackNum)*1.0;
							break;
						case '-':
							iRes = (iFrontNum - iBackNum)*1.0;
							break;
						case '*':
							iRes = (iFrontNum * iBackNum)*1.0;
							break;
						case '/':
							iRes = (iFrontNum / iBackNum)*1.0;
							break;
							//如果是"("或者是")"
						default:
							break;
						}
						//i++;//由于要循环遍历,计数器不变,仍停留在当前运算符,循环与前面的运算符比较
						//将计算后的结果压入数字栈
						stackNum.push(iRes);

						//易错,需要将栈顶高优先级操作符弹出,将当前低优先级操作进栈
						stackOpe.pop();
						//stackOpe.push(sInput[i]);
						if('('==stackOpe.top() && ')'==sInput[i])
						{
							break;
						}
						
					}//else
				}//else
			}//else if
		}//for
		printf("%.2f\n",stackNum.top());
	}
	system("pause");
	getchar();
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: