C++ 双栈实现表达式求值

C++双栈实现表达式求值

好程序就是用更少的代码实现更多的功能,该程序无疑做到了这一点。
但在使用更少的代码实现功能的同时,代码也更难让人理解。
程序中的算法与思路均来源于网络,但我知道是伟大的计算机前辈们发明了它。

我经过了很长时间的调试和画图才理解并仿照出了这个程序,但在极少数情况,仍会出现在我意料之外的计算错误,由于此时的表达式较长,我也没有再去深究。

功能:
该程序实现了输入一个表达式求值的功能,支持多重小括号、±*/%运算,最终结果为一个整数,仅支持正整数运算,输入不正确的数值会导致最终计算结果错误。

运行效果:
1
2

编译环境:Windows VS2019

思路:
输入的表达式保存到字符串中,通过遍历该字符串,找到字符串中的数字和运算符,再根据规则处理他们。

注意:
该程序仅可以计算正整数的表达式,且最终结果非百分百正确,仅可用于学习参考。

代码:

#include <iostream>
#include "mystack.h"
using namespace std;

class Calcu
{
private:
	string expr;			//用于输入的字符串
	int num_1 = 0,num_2 = 0;//记录运算数
	char oper = 0;			//记录运算符
	Stack<int> numstack;	//数据栈
	Stack<char> operstack;	//运算符栈
	bool sign = false;		//第一次标记
	int strsize = 0;		//存储表达式的长度

	//判断运算符优先级函数
	inline int Priority(char oper)
	{
		switch (oper)
		{
		case '+':
		case '-':
			return 1;
		case '*':
		case '/':
		case '%':
			return 2;
		case '(':
		case ')':
			return 0;	//小括号优先级为0为程序必要
		case 0:
		default:
			return -1;	//程序必要
		}
	}

public:
	//计算主函数
	void Function()
	{
		//输入表达式
		cout << endl << "请输入要计算的表达式:(0不会参与运算)" << endl << endl;
		cin >> expr;

		//主循环
		strsize = expr.size();		//记录字符串的长度
		for (int i = 0; i < strsize; i++)
		{
			//转换数字必要
			num_1 = 0;
			num_2 = 0;

			//将一个或多个数字字符转换为一个数
			while (expr[i] >= '0' && expr[i] <= '9')
			{
				num_1 = expr[i] - '0';
				num_2 = num_2 * 10 + num_1;
				i++;
			}
			
			//将当前数入栈(0无法入栈)
			numstack.push(num_2);

			//如果符号栈为空,则符号直接入栈
			if (operstack.empty())
			{
				operstack.push(expr[i]);
				continue;
			}

			//如果当前运算符优先级高于栈顶元素的优先级(下标越界的不存在的运算符优先级为最低),或为左括号,则将该符号入栈
			if (Priority(expr[i]) > Priority(operstack.gettop()) || expr[i] == '(')
			{
				operstack.push(expr[i]);
				continue;
			}
			
			//当前符号优先级小于等于栈顶运算符优先级执行运算循环
			while (Priority(expr[i]) <= Priority(operstack.gettop()))
			{
				//将栈中的两个数据取出
				num_1 = numstack.pop();
				num_2 = numstack.pop();

				//根据运算符号计算不同的算式
				switch (operstack.pop())	//运算符栈出栈,保存符号
				{
				case '+':
					num_2 += num_1; break;
				case '-':
					num_2 -= num_1;	break;
				case '*':
					num_2 *= num_1; break;
				case '/':
					num_2 /= num_1; break;
				case '%':
					num_2 %= num_1;
				}

				numstack.push(num_2);				//将计算结果压栈

				if (expr[i] == ')')					//字符位为)时 (出栈,i++
				{
					operstack.pop();				
					i++;
				}

				if (operstack.gettop() == '(')		//运算符栈顶为(时,入栈其他字符
					break;

				if(operstack.empty())				//当符号栈为空时退出循环
					break;
			}

			//不要忘记将数压入栈中后,还要将这个数后面的运算符也压入栈
			if (i < strsize)
				operstack.push(expr[i]);
		}

		//最后输出计算结果:
		//cout << num_2 << endl;
		cout << "结果:" << numstack.pop() << endl << endl;
	}

};

//主函数
int main()
{
	system("title 双栈计算器");          //设置标题

	while (true) Calcu().Function();    //计算函数

	return 0;
}

//1+3%4-4*(4+5*(6+7-3*(4-5*(6-8)+8)-6)-14)+2*(8-(3+1-1))+12*(15+12)+800-(10*10)-1258+100

"mystack.h"栈类头文件代码(链式存储)

#pragma once

#include <iostream>
using namespace std;

//栈类,使用链式存储结构实现
template <class T>
class Stack
{
private:
	struct Node						//节点结构
	{
		T data;
		Node* next;
	};

	Node* top = NULL, * p1 = NULL;	//栈顶指针,工作指针

public:

	~Stack()						//析构链表内存释放内存
	{
		p1 = top;

		while (p1)
		{
			top = top->next;
			delete p1;
			p1 = top;
		}
	}

	void push(T temp)		//压栈
	{
		if(!temp)			//入栈的数如果是0则直接返回
			return;

		p1 = new Node;

		p1->data = temp;
		p1->next = top;
		top = p1;
	}

	T pop()					//弹栈 删除栈顶元素,并返回这个元素
	{
		if (!top)
		{
			//cout << "栈空" << endl;
			return 0;
		}
		
		T temp;
		p1 = NULL;

		temp = top->data;

		p1 = top->next;
		delete top;
		top = p1;

		return temp;
	}

	T gettop()			//获取栈顶元素
	{
		if (top)
			return top->data;

		//cout << "获取时栈空" << endl;
		return 0;
	}

	bool empty()		//判断栈是否为空
	{
		return !top;
	}

	void popput()		//弹出栈内所有元素并输出
	{
		while(top)
		{
			cout << pop();
			top = top->next;
		}
	}
};

不足之处:
该程序功能较少,且计算结果在特定情况下会出错,没有实际意义。


感谢大家的支持。

原创文章 20 获赞 24 访问量 8348

猜你喜欢

转载自blog.csdn.net/qq_46239972/article/details/105559857