【C/C++ 08】简单计算器

一、题目

输入算术表达式,可包含空格,检查算术表达式的合法性,若算术表达式不合法,打印错误类型,若合法,则进行运算,打印计算结果。

二、算法

  1. 将输入的算术表达式字符串去除空格。

  2. 检查输入的算术表达式的合法性,判断算式首字符是否合法(只能是前括号或正负号),判断括号是否匹配,判断连续字符是否合法(运算符后面可跟左括号,右括号后面可跟运算符,左括号后面可跟加减号表正负,左右括号之间不能直接相连,数字后面不能直接跟左括号)。

  3. 构造符号栈和数据栈对合法的算术表达式进行计算,计算的过程就是从数据栈取出两个数据和符号栈取出一个数据,然后计算得到一个结果,再将结果压入数据栈。

三、代码

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

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

vector<char> g_opt = { '+', '-', '*', '/'};

void RemoveSpaces(char* input)
{
	for (int i = 0; i < strlen(input); ++i)
	{
		if (input[i] == ' ')
		{
			for (int j = i; j < strlen(input); ++j)
			{
				input[j] = input[j + 1];
			}
			--i;
		}
	}
}

bool CheckInput(char* input)
{
	stack<char> bracket;	// 用于判断括号的合法性

	for (int i = 0; i < strlen(input); ++i)
	{
		if (!isdigit(input[i]))
		{
			if (find(g_opt.begin(), g_opt.end(), input[i]) == g_opt.end()
				&& input[i] != '(' && input[i] != ')')
			{
				cout << "存在非法字符 " << input[i];
				return false;
			}

			if (input[i] == '(')
			{
				bracket.push(input[i]);
			}
			else if (input[i] == ')')
			{
				if (bracket.empty())
				{
					cout << "括号不匹配";
					return false;
				}
				else
				{
					bracket.pop();
				}
			}

			// 第一个字符必须是数字或正负号或左括号
			if (i == 0 && input[i] != '+' && input[i] != '-' && input[i] != '(')
			{
				cout << "首字符错误";
				return false;
			}

			if (!isdigit(input[i + 1]))
			{
				if (input[i] == '(')
				{
					// 左括号后面可以跟加减表示正负
					if (input[i + 1] == '*' || input[i + 1] == '/' || input[i + 1] == ')')
					{
						cout << "出现连续符号 " << input[i + 1];
						return false;
					}
				}
				else if (input[i] == ')')
				{
					// 有括号后面不能直接跟前括号,可以跟操作符
					if (input[i + 1] == '(')
					{
						cout << "出现连续符号 " << input[i + 1];
						return false;
					}
				}
				else
				{
					// 操作符后面可以跟左括号
					if (input[i + 1] != '(')
					{
						cout << "出现连续符号 " << input[i + 1];
						return false;
					}
				}
			}
		}
		else
		{
			// 数字后面不能直接跟左括号
			if (input[i + 1] == '(')
			{
				cout << "括号位置错误 " << input[i + 1];
				return false;
			}
		}
	}

	if (!bracket.empty())
	{
		cout << "括号不匹配";
		return false;
	}

	return true;
}

bool PopCal(stack<int>& datas, stack<char>& symbols)
{
	if (datas.size() < 2 || symbols.empty())
		return false;

	if (symbols.top() == '(')
	{
		symbols.pop();
		return false;
	}

	int x = datas.top();
	datas.pop();
	int y = datas.top();
	datas.pop();
	char opt = symbols.top();
	symbols.pop();

	int res = (unsigned int)-1;
	if (opt == '+')
		res = x + y;
	else if (opt == '-')
		res = x - y;
	else if (opt == '*')
		res = x * y;
	else if (opt == '/')
		res = x / y;
	datas.push(res);
	return true;
}

int Calculate(char* input)
{
	// 数据栈和符号栈
	stack<int> datas;
	stack<char> symbols;

	int flag = 1;	// 1表示正,-1表示负数
	for (int i = 0; i < strlen(input); ++i)
	{
		if (isdigit(input[i]))
		{
			// 将连续数字字符转为整型数据存入数据栈
			string digit = "";
			digit += input[i];
			while (isdigit(input[i + 1]))
			{
				++i;
				digit += input[i];
			}
			int num = atoi(digit.c_str());
			datas.push(num * flag);
			flag = 1;

			// 数据压栈后发现栈顶是乘除号,直接进行计算
			if (!symbols.empty() && (symbols.top() == '*' || symbols.top() == '/'))
				PopCal(datas, symbols);
		}
		else
		{
			// 左括号的优先级最高
			if (input[i] == '(')
			{
				symbols.push(input[i]);
				continue;
			}

			// 判断负号
			if (i == 0 || input[i - 1] == '(')
			{
				if (input[i] == '-')
					flag = -1;
				continue;
			}

			if (input[i] == '*' || input[i] == '/')
			{
				// 乘除符号直接压入符号栈
				symbols.push(input[i]);
			}
			else if (input[i] == '+' || input[i] == '-')
			{
				// 若符号栈存有加减号未计算,先计算再将加减号压栈
				if (!symbols.empty() && (symbols.top() == '+' || symbols.top() == '-'))
				{
					PopCal(datas, symbols);
				}
				symbols.push(input[i]);
			}
			else if (input[i] == ')')
			{
				if (symbols.top() == '(')
				{
					// 表示括号括住了数字,而不是表达式
					symbols.pop();
				}
				else
				{
					// 循环出栈计算,直到遇到左括号
					while (PopCal(datas, symbols))
					{}
				}
			}
		}
	}

	// 循环出栈计算
	while (PopCal(datas, symbols))
	{}
	
	return datas.top();
}

int main()
{
	while (1)
	{
		char input[128];
		cout << "请输入算术表达式:";
		fgets(input, sizeof(input), stdin);
		input[strlen(input) - 1] = 0;

		RemoveSpaces(input);
		if (strcmp(input, "exit") == 0)
			break;
		if (!CheckInput(input))
		{
			cout << ",表达式输入格式错误,请重新输入!" << endl;
			continue;
		}

		int res = Calculate(input);
		cout << input << " = " << res << endl;
	}

	return 0;
}

四、测试

相关推荐
陌小呆^O^2 分钟前
Cmakelist.txt之win-c-udp-client
c语言·开发语言·udp
cherub.6 分钟前
深入解析信号量:定义与环形队列生产消费模型剖析
linux·c++
I_Am_Me_18 分钟前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
暮色_年华20 分钟前
Modern Effective C++item 9:优先考虑别名声明而非typedef
c++
重生之我是数学王子28 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
Ai 编码助手30 分钟前
使用php和Xunsearch提升音乐网站的歌曲搜索效果
开发语言·php
学习前端的小z34 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
神仙别闹41 分钟前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#
XINGTECODE43 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
我们的五年1 小时前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习