C++双栈实现表达式求值
好程序就是用更少的代码实现更多的功能,该程序无疑做到了这一点。
但在使用更少的代码实现功能的同时,代码也更难让人理解。
程序中的算法与思路均来源于网络,但我知道是伟大的计算机前辈们发明了它。
我经过了很长时间的调试和画图才理解并仿照出了这个程序,但在极少数情况,仍会出现在我意料之外的计算错误,由于此时的表达式较长,我也没有再去深究。
功能:
该程序实现了输入一个表达式求值的功能,支持多重小括号、±*/%运算,最终结果为一个整数,仅支持正整数运算,输入不正确的数值会导致最终计算结果错误。
运行效果:
编译环境: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;
}
}
};
不足之处:
该程序功能较少,且计算结果在特定情况下会出错,没有实际意义。
感谢大家的支持。