寒假编的计算器
  • 板块灌水区
  • 楼主cp1227
  • 当前回复16
  • 已保存回复16
  • 发布时间2022/2/9 08:44
  • 上次更新2023/10/28 09:21:02
查看原帖
寒假编的计算器
459171
cp1227楼主2022/2/9 08:44

寒假无聊,编个计算器玩玩

我之前发过一次计算器的帖子,但是有bug所以我把bug修复后想再发一次(欢迎找bug)

写在前面:

  • 使用Visual Studio 2022编写
  • 支持加减乘除,可以套多个括号
  • 我的思路是把表达式先转换成后缀表达式,再用栈进行运算(因为中缀表达式运算我不会编,百度了也看不懂QoQ)

参考:


代码(有点难看)

#include<iostream>
#include<stdio.h>
#include<stack>
#include<cmath>
using namespace std;

stack<double>a;//后缀表达式使用的栈
stack<char>b;//中缀表达式转后缀表达式需要栈

char c[10000];//'c':存储后缀表达式
char s[10000];//'s':把输入的'z'经过内部处理转换成's'(中缀改)
char z[10000];//'z':输入的字符数组(中缀)

int ss;//'s'字符数组对应的下标
int cc;//'c'字符数组对应的下标
double  t1 = 0.0, t2 = 0.0;//后缀表达式计算的临时变量

bool pd1()//中缀表达式转后缀表达式的判断
{
	if ((!b.empty()) && (b.top() == '+' || b.top() == '-' || b.top() == '*' || b.top() == '/')) return 1;
	else return 0;
}

bool pd2()//中缀表达式转后缀表达式的判断
{
	if ((!b.empty()) && (b.top() == '*' || b.top() == '/')) return 1;
	else return 0;
}

void zq()//后缀表达式计算时从栈顶取两个数字
{
	t2 = a.top();
	a.pop();
	t1 = a.top();
	a.pop();
}

void sj()//中缀表达式转后缀表达式的出栈(<stack>b)操作
{
	c[cc] = b.top();
	cc++;
	b.pop();
}

void jf(int x)//中缀表达式转后缀表达式的加减号处理
{
	if (pd1() == 1) while (pd1() == 1) sj();
	if (x == 1) b.push('+');
	else b.push('-');
	ss++;
}

void cf(int x)//中缀表达式转后缀表达式的乘除号处理
{
	if (pd2() == 1) while (pd2() == 1) sj();
	if (x == 1) b.push('*');
	else b.push('/');
	ss++;
}

void zh()//中缀表达式转后缀表达式
{
	int t = strlen(s);//'s'字符数组的临时下标
	while (ss < t) 
	{
		if ('0' <= s[ss] && '9' >= s[ss] || s[ss] == '.') 
		{
			while ('0' <= s[ss] && '9' >= s[ss] || s[ss] == '.') 
			{
				c[cc] = s[ss];
				cc++;
				ss++;
			}
			c[cc] = '@';
			cc++;
		}
		else if (s[ss] == '+') jf(1);
		else if (s[ss] == '-') 
		{
			if (ss == 0 || ('0' > s[ss - 1] || '9' < s[ss - 1]) && s[ss - 1] != ')') 
			{
				c[cc] = '~';
				cc++;
				ss++;
			}
			else jf(2);
		}
		else if (s[ss] == '*') cf(1);
		else if (s[ss] == '/') cf(2);
		else if (s[ss] == '(') 
		{
			b.push('(');
			ss++;
		}
		else if (s[ss] == ')') 
		{
			while (b.top() != '(') sj();
			b.pop();
			ss++;
		}
	}
	while (!b.empty()) sj();
}

void js()//后缀表达式计算
{
	int t = 0;//'c'字符数组的临时下标

	int tmp = 0;//小数点判断的临时变量
	int f = 0;//小数点判断

	int f1 = 0;//负号判断(我把负号换成了'~'为了与减号分开)

	double num1 = 0.0;//存储整数部分
	double num2 = 0.0;//存储小数部分
	while (t < cc) 
	{
		if (('0' <= c[t] && '9' >= c[t]) || c[t] == '~') 
		{
			num1 = 0.0;
			num2 = 0.0;
			f = 0;
			tmp = 0;
			if (c[t] == '~') 
			{
				f1 = 1;
				t++;
			}
			else 
			{
				while (c[t] != '@') 
				{
					if (f == 1) 
					{
						num2 *= 10;
						num2 += c[t] - '0';
						tmp++;
					}
					if (c[t] == '.') f = 1;
					if (f == 0) 
					{
						num1 *= 10;
						num1 += c[t] - '0';
					}
					t++;
				}
				a.push(num1 + num2 / pow(10, tmp));
				if (f1 == 1) 
				{
					a.top() *= -1;
					f1 = 0;
				}
			}
		}
		if (c[t] == '@')t++;
		else if (c[t] == '+') 
		{
			zq();
			a.push(t1 + t2);
			t++;
		}
		else if (c[t] == '-') 
		{
			zq();
			a.push(t1 - t2);
			t++;
		}
		else if (c[t] == '*') 
		{
			zq();
			a.push(t1 * t2);
			t++;
		}
		else if (c[t] == '/') 
		{
			zq();
			a.push(t1 / t2);
			t++;
		}
	}
}

void jz()//把'z'字符数组经过转换赋给's'字符数组(1--(2+3)===>1--1*(2+3))
{
	for (int i = 0; i < strlen(z); i++) 
	{
		if (z[i] == '-' && z[i + 1] == '(') 
		{
			s[ss] = '-';
			ss++;
			s[ss] = '1';
			ss++;
			s[ss] = '*';
			ss++;
		}
		else 
		{
			s[ss] = z[i];
			ss++;
		}
	}
	ss = 0;
}

int main() 
{
	char t = '@';
	printf("计算器\n");
	while (t == '@') 
	{
		while (!a.empty()) a.pop();
		while (!b.empty()) b.pop();
		ss = 0;
		cc = 0;
		memset(s, '\0', sizeof(s));
		memset(c, '\0', sizeof(c));
		memset(z, '\0', sizeof(z));
		printf("请输入\n");
		cin >> z;
		jz();
		zh();
		js();
		printf("%.10lf\n按@键继续,其他键跳出\n", a.top());//输出栈顶数字
		cin >> t;
	}
	return 0;
}
2022/2/9 08:44
加载中...