制作计算器2

/*STL 中栈的使用方法(stack)
基本操作:
#include <stack>
stack <char> s
s.push(x) 将x加入栈中,即入栈操作
s.pop() 出栈操作(删除栈顶),只是出栈,没有返回值
s.top() 返回第一个元素(栈顶元素)
s.size() 返回栈中的元素个数
s.empty() 当栈为空时,返回 true
*/

/*
思路:输入一个字符串,建立两个栈:num,op。分别用于存储数字和运算符号,
从第一个元素到最后一个元素遍历:
如果遇到数字,就把该数字所在的数字串如栈num,判断下一个元素
如果遇到左括号,直接进栈,判断下一个元素
如果遇到右括号,就对栈op,num,一直更新计算数据,直到栈op顶部遇到左括号
如果遇到等号,把栈op,num,一直更新计算数据,直到栈op顶部为'#'
如果遇到加减乘除乘方的运算符,判断该运算符和栈顶运算符优先级的关系,若栈顶高于当前运算符,
先更新计算栈中的元素,直到当前运算符高于栈顶运算符,此时当前运算符入栈op;
*/

//下边为百度百科给的算法详细解释

/*将一个普通的中序表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆波兰式的栈S2(空栈),
S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。
可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,
如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,
否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,
最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!*/

/*计算方法:
新建一个表达式, 如果当前字符为变量或者为数字,则压栈,如果是运算符,
则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。*/

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <cmath>

using namespace std;

stack <char> op;
stack <double> num;
char str[1000];
int i = 0,len;

double getnum()//通过输入的字符串分割得到数字
{
	int j = 0;
	char s[50];
	while ((i < len) && (str[i] >= '0' && str[i] <= '9' || str[i] == '.'))
		s[j++] = str[i++];
	s[j] = '\0';
	return atof(s);//atof作用:把字符串s变为double形数据返回
}

int priority(char ch)//根据字符返回对应的优先级别
{
	switch (ch) 
	{
	case '(': return 0; break;
	case '+': return 1; break;
	case '-': return 1; break;
	case '*': return 2; break;
	case '/': return 2; break;
	case '^': return 3; break;
	case '#': return -1; break;
	}
}

double calc(double a, char o, double b)//计算a,o,b,返回结果
{
	switch (o)
 	{
 	case '+': return a + b;
 	case '-': return a - b;
 	case '*': return a * b;
 	case '/': return a / b;
 	case '^': return pow(a, b);
 	}
}

void back()//将num栈顶的两个数出栈,op栈顶一个数出栈,将计算结果进栈num
{
	double b = num.top(); num.pop();
	double a = num.top(); num.pop();
	char o = op.top(); op.pop();
	num.push(calc(a, o, b));
}

double cal()//核心程序,遍历输入的字符串并返回最终计算结果
{
	i = 0;
	len = strlen(str);//i和len要初始化
	while (i < len)//遍历整个字符串
	{
		if (str[i] >= '0' && str[i] <= '9')//如果遇到数字
		{
			num.push(getnum());//把这个数字的字符串所对应的数入栈num
			continue;//结束本次循环
		}
		switch (str[i])
		{
		case '(':	op.push(str[i++]); break;//遇到左括号进栈op
		case ')'://遇到右括号对栈op处理,没遇到一个运算符就计算栈op上边两个数,直到遇到'(';
			while (op.top() != '(')
				back();//不断更新栈op和num
			op.pop();//把左括号出栈
			i++;//进行下一个字符的判断
			break;
		case '=':
			while (op.top()!='#')//把栈op和num剩余的元素计算完
				back();
			return num.top();//最后栈num只剩一个元素,即为最后的结果
		default ://即为加减乘除乘方的情况
			while (priority(op.top()) >= priority(str[i]))//根据优先级决定是否op出栈
				back();
			op.push(str[i++]);//到当前字符优先级高于栈顶优先级,进栈op
		}
	}
}

int main()
{
	printf("请保证你的输入是合理的\n");
	while (scanf("%s", str) != EOF)//输入的式子不含空格和回车,最后输入回车得到输出结果
	{
		while (!op.empty())	op.pop();
		while (!num.empty())	num.pop();//初始化清空两个栈
		op.push('#');//栈底放一个'#',后来比较优先级要用
		printf("结果为:  %.6lf\n", cal());
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值