## 设计并实现一个整型算术表达式计算器(C++)包含+-*/()运算,含详细解释,附源码,可直接运行。

设计并实现一个整型算术表达式计算器(C++)

题目要求是: 处理整型算术运算表达式,即运算符至少包含±*/()

 上个学期学习了数据结构这门课程,着实被课后作业给整惨了。
 在自己做作业时也切实体会到了修改BUG的不易,以及在网上找不到适合的源码的困难。所以我决定自己写。
 并且现在是暑假也闲来无事,决定写一篇博客,来分享一下自己的代码,同时也希望我们一起学习一起进步。

******这个作业应该是我这门课第一个有难度的作业。首先实现整形计算器是需要数据结构栈的。我没有用C++STL库中自带的stack,而是使用的我们老师上课所讲的栈(后面的作恶也有让体会使用stl,具体函数功能其实都差不多)。注意,这里需要两种类型的栈,一个存放数据,一个存放运算符。所以我将栈定义为了模板类。
先简单说一下我们自己写的栈结构吧。我们有一个枚举类型errorcode,这个不用太在意,就是用来判断函数是否成功调用,返回调用的结果。栈的具体功能有判断空,取栈顶,入栈出栈等。由于使用的是链栈结构,所以判断满没什么实际意义。比较需要注意的就是取栈顶元素时,是通过函数get_top(T& x)形参引用类型传入的,即调用完这个函数之后,传入的实参值会改变为我们的栈顶元素的值,也就达到了取栈顶的目的。至于其他函数我自己觉得还是非常好理解的。
然后我们说我们的计算器吧。对于计算器的输入,我使用了string类型,用来存储初始输入的表达式,当表达式字符入栈时,因为数字字符输入的是对应ASCII码,需要将输入的数字字符,通过对应的ASCII码转化成对应的十进制数字。为此我定一个change()函数实现这一操作。而且,有可能输入的是多位的数字,所以需要判断一下输入的是几位,这个功能在main函数中实现的。
对于字符串,需要从左向右一个一个读,对于数字字符和运算符需要进入不同的栈,为了判断每个字符需要进入哪个栈,我也定义了一个isnumber()函数用来判断当前读取的字符是数字还是运算符。
如果当前需要判断的字符是运算符,那么我们还需要判断一下,该运算符是入栈还是进行栈顶运算符的计算,只有当当前运算符的优先级比栈顶运算符的优先级高,或者当前为左括号时,才会进行入栈操作。当当前运算符为右括号且栈顶为左括号时,左括号出栈且不进行运算,直接进入下一个字符的判断。只有当当前运算符为#且栈顶运算符也为#时,此时所有运算符均进行完了运算,那么运算结束,数据栈的栈顶即为运算结果。
上一个段落我们分析了种种情况。为此我设置了两个函数,一个priority()函数,用来判断运算符的优先级。一个jisuan()函数用来判断当前需要进行何种运算,并完成对数据栈的操作。
在主函数中,我设置了一个很大的for循环,用来逐个对输入的表达式进行扫描,并在循环体嵌套了许多的if else语句用来判断针对当前运算符应该进行何种情况的操作。比如,当前如果是运算符的话,如何判断他与当前栈顶运算符的优先级,判断完成后,若当前的较高,则会进行运算,并且当前栈顶运算符会出栈。然后在进行与下一个栈顶运算符的比较。因为这个我专门设置了一个while循环,直到当前运算符入栈或者为右括号时与左括号对应的操作,或者为#号时与栈顶#号的操作。
还有一些关于多位数数字的输入问题,因为对于用string类型的数据来说,输入一个多位数字表示多个字符,如果直接判断该数字的最高位直接入栈会出现错误,因此我也在判断其是否为数字字符后边使用了while循环,用来将该多位数字送去数据栈,详细可见我的代码。
这样,根据上述完成后,最后数据栈栈顶即为最后的运算结果。
啰嗦完之后,就直接上代码了,可以直接编译运行,输入表达式即可。

栈以及栈中每一个数据结构的模板

#ifndef STACK
#define STACK
enum errorcode {
	success, underflow, overflow
};
template<class T>                      //结构体模板,因为要使用具有不同数据类型的结构体,所以使用了模板类
struct node {
	T data;
	node<T>* next;
};
template<class T>
class stack {
public:
	stack();
	~stack();
	bool empty() const;
	bool full() const;                          //基本无意义
	errorcode get_top(T& x) const;
	errorcode push(const T x);
	errorcode pop();
private:
	int count;
	node<T>* top;
};
template<class T>
stack<T>::stack() {
	count = 0;
	top = NULL;
}
template<class T>
bool stack<T>::empty() const {
	return count == 0;
}
template<class T>
errorcode stack<T>::get_top(T& x)const {
	if (empty())
		return underflow;
	x = top->data;
	return success;
}
template<class T>
errorcode stack<T>::push(const T x) {
	node<T>* s = new node<T>;
	s->data = x;
	s->next = top;
	top = s;
	count++;
	return success;
}
template<class T>
errorcode stack<T>::pop() {
	if (empty()) return underflow;
	node<T>* u;
	u = top;
	top = top->next;
	delete u;
	count--;
	return success;
}
template<class T>
stack<T>::~stack() {
	while (!empty())
		pop();
}
#endif // !stack

main函数

#include<iostream>
#include<string>
#include"stack模板.h"
using namespace std;

int priority(char x);//判断运算符优先级
int change(char x);//数字ASCII码转数字
bool isnumber(char x);//判断输入的是否是数字
int jisuan(char x, stack<int>& num1);//判断符号运算属性,并运算返回结果
int main()
{
	stack<int> num;                        //存储数据
	stack<char> oper;                    //存储符号
	int p, i;                           //p用来取运算完后数据栈的栈顶,既最后的运算结果
	string s;
	cout << "请输入一个算数表达式:";
	cin >> s;
	s += '#';
	oper.push('#');               //给字符栈一个初始的值#
	for (i = 0; i < s.size(); i++)
	{
		if (isnumber(s[i]))            //判断当数字为多位时适当改变函数
		{
			int j = 0, t = 1, sum = 0, p;
			while (isnumber(s[i + j]))       //j记录是几位的数字
				j++;
			p = j;                          //保留下j
			while (j > 0)                       //sum求出这个数字
			{
				sum += change(s[i + j - 1]) * t;
				t *= 10;
				j--;
			}
			num.push(sum);            //sum入栈
			i = i + p - 1;              //i的值跳转
		}
		else
		{
			int k = 1;
			char x, y;                           //x取当前字符栈栈顶元素
			oper.get_top(x);
			while (k)
			{
				if (priority(s[i]) > priority(x) || s[i] == '(')             //当前字符优先级如果大于栈顶则入栈
				{
					oper.push(s[i]);
					break;
				}
				else                          //如果不是则使用计算函数,并将结果送入数据栈
				{
					if (priority(s[i]) == priority(x) && priority(s[i]) == 0 || priority(s[i]) == priority(x) && priority(s[i]) == -1)    //既判断左右括号见面,如果当前是右括号,而字符栈中是左括号,则不计算,且左括号出栈且进入下个字符判断
					{
						oper.pop();
						break;
					}
					else
					{
						num.push(jisuan(x, num));        //计算结果,并将结果送去数据站
						oper.pop();             //当前栈顶元素出栈             
						oper.get_top(y); //字符栈栈顶出栈后再判断当前字符与当前栈顶的优先级,将y的值给x,进入while循环
						x = y;
					}
				}
			}
		}
	}
	num.get_top(p);              //数据栈当前栈顶就是最终运算结果
	for (i = 0; i < s.size() - 1; i++)
		cout << s[i];
	cout << '=' << p << endl;           //输出运算结果
	return 0;
}

//判断运算符优先级
int priority(char x) {
	if (x == '+' || x == '-')
		return 1;
	else if (x == '*' || x == '/')
		return 2;
	else if (x == '(' || x == ')')
		return 0;
	else
		return -1;
}
//数字ASCII码转数字
int change(char x)
{
	int y;
	y = x - 48;
	return y;
}
//判断输入的是否是数字
bool isnumber(char x)
{
	if (x >= '1' && x <= '9')
		return 1;
	else
		return 0;
}
//判断符号运算属性,并运算返回结果
int jisuan(char x, stack<int>& num1)
{
	int a, b, c;
	if (x == '+')
	{
		num1.get_top(a);
		num1.pop();
		num1.get_top(b);
		num1.pop();
		c = a + b;
	}
	else if (x == '-')
	{
		num1.get_top(a);
		num1.pop();
		num1.get_top(b);
		num1.pop();
		c = b - a;
	}
	else if (x == '*')
	{
		num1.get_top(a);
		num1.pop();
		num1.get_top(b);
		num1.pop();
		c = a * b;
	}
	else if (x == '/')
	{
		num1.get_top(a);
		num1.pop();
		num1.get_top(b);
		num1.pop();
		c = b / a;
	}
	return c;
}
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值