实验课的作业,要求是用顺序栈实现可以四则运算的计算器,大概的要求就是用户输入一行中缀表达式,编写程序让计算机将中缀转为易于计算的后缀表达式,在将后缀表达式的结果计算出来。
注意这里只支持十位数以内的数字运算,作业ddl来不及不想搞了,但是上网参考了一下别人的代码十位数以上的也不难,之后有时间再改进。刚开始敲的时候直接参考了清华大学出版社殷人昆那版的《数据结构》中的顺序栈和Calculator模板类,问题太多了改错改了一堆,postfix函数也不是适用的,所以在调试的时候花的时间比我预计的多出很多........发出来纪念一下
SeqStack.h
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
const int stackIncreament = 10; //栈溢出时扩展空间的增量
template<class T>
class SeqStack {
public:
SeqStack() { elements = 0; top = -1; maxSize = 0; }
SeqStack(int sz = 50); //构造函数
~SeqStack() { delete[] elements; } //析构
void Push(const T& x); //如果栈满了就要溢出处理,否则就入栈到栈顶
T Pop(); //退出栈的元素通过引用型参数x返回
T getTop(); //获取栈顶元素的值
bool IsEmpty()const { return(top == -1) ? true : false; }
bool IsFull()const { return(top == maxSize - 1) ? true : false; }
int getSize()const { return top + 1; } //返回栈中元素个数
void MakeEmpty() { top = -1; } //清空栈的内容
private:
T* elements; //存放栈中元素的栈数组
int top; //栈顶指针
int maxSize; //栈的最大容量
void overflowProcess(); //栈的溢出处理
};
template<class T>
SeqStack<T>::SeqStack(int sz) :top(-1), maxSize(sz) { //先执行初始化列表
elements = new T[maxSize];
if (elements==nullptr) {
cout << "栈存储空间分配失败!" << endl; exit(1);
}
}
template<class T>
void SeqStack<T>::overflowProcess() { //私有函数:扩充栈存储空间
T* newArray = new T[maxSize + stackIncreament];
if (newArray = nullptr) { cout << "存储分配失败!" << endl; exit(1); }
for (int i = 0; i <= top; i++)
newArray[i] = elements[i]; //逐个将栈内原有元素放入新的
maxSize = maxSize + stackIncreament; //更新最大容量
delete[] elements; //删掉旧的
elements = newArray; //给新的正名
}
template<class T>
void SeqStack<T>::Push(const T& x) {
if (IsFull() == true) { cout << "栈满,自动扩充容量!" << endl; overflowProcess(); }//栈满就做溢出处理
elements[++top] = x; //栈顶指针先加1再放进栈
cout << "元素 " << x << " 成功推入栈顶" << endl;
}
template<class T>
T SeqStack<T>::Pop() {
if (IsEmpty() == true) { cout << "栈为空!" << endl; return false; }
T x = elements[top--]; //先存出数据再让指针退1
return x;
}
template<class T>
T SeqStack<T>::getTop() {
if (IsEmpty() == true)return false;
T x;
x = elements[top];
return x;
}
calculate.h
#pragma once
#include <cmath>
#include <string>
#include "SeqStack.h"
#include <iostream>
using namespace std;
//模拟一个简单的计算器,对从键盘读入的中缀表达式先转化为后缀表达式再求值
template<class T>
class Calculator {
public:
Calculator(int sz) :s(sz) { }//给顺序栈开辟了空间
void postfix(string mid_str); //中缀转后缀
void Run(); //执行表达式运算
void Clear();
private:
char RPN_ch[100];
SeqStack<T> s; //因为我们计算器是针对后缀表达式的,所以这个栈中存放的必须是后缀表达式
void AddOperand(T& value); //进操作数栈
bool Get2Operands(T& left, T& right);//从栈中退出两个操作数
void DoOperator(char op); //形成运算指令进行计算
};
template<class T>
void Calculator<T>::DoOperator(char op) {
T left, right, value; //取两个操作数,根据操作符op形成运算指令并计算
bool result;
result = Get2Operands(left, right); //取两个操作数
if (result == true) //操作数取成功了就开始计算并将结果Push进栈
switch (op) {
case'+':value = left + right; s.Push(value); break;
case'-':value = left - right; s.Push(value); break;
case'*':value = left * right; s.Push(value); break;
case'/':if (right == 0.0) { //检查:除数不能为零
cerr << "Divide by 0!" << endl; Clear(); //报错清栈
}
else { value = left / right; s.Push(value); } break;
} //else Clear(); //取数不成功,result==false
if (result != true) {
cout << "取数不成功,无法进行下一步运算!" << endl; Clear();
}
}
template<class T>
bool Calculator<T>::Get2Operands(T& left, T& right) {
if (s.IsEmpty() == true)
{
cerr << "缺少右操作数!" << endl; return false; //栈空,报错
}
else right=s.Pop(); //取出右操作数
if (s.IsEmpty() == true)
{
cerr << "缺少左操作数!" << endl;
return false;
}
else left=s.Pop();
return true; //代表成功祛除了两个操作数
}
template<class T>
void Calculator<T>::AddOperand(T& value) {
s.Push(value); //将操作数的值Push进操作数栈
}
template<class T>
void Calculator<T>::Run() {
T newOperand; //用来存运算操作数
int i = 0;
while (RPN_ch[i] != '=') {
switch (RPN_ch[i]) {
case'+':case'-':case'*':case'/':
DoOperator(RPN_ch[i]); break; //如果是操作符,那就可以执行计算
default:
cin.putback(RPN_ch[i]); //将字符放回输入流
cin >> newOperand; //重新从输入流中读操作数
AddOperand(newOperand); //将操作数放入栈中
break;
}
i++;
}
T result=s.getTop();
cout << "表达式运算结果为:" << result<< endl;
}
template<class T>
void Calculator<T>::Clear() {
s.MakeEmpty(); //清栈
}
//栈内优先级
int isp(char op) {
int priority = 0;
if (op == '#') {
priority = 0;
}
else if (op == '(') {
priority = 1;
}
else if (op == ')') {
priority = 6;
}
else if (op == '+' || op == '-') {
priority = 3;
}
else if (op == '*' || op == '/') {
priority = 5;
}
return priority;
}
//栈外优先级
int icp(char op) {
int priority = 0;
if (op == '#') {
priority = 0;
}
else if (op == '(') {
priority = 6;
}
else if (op == ')') {
priority = 1;
}
else if (op == '+' || op == '-') {
priority = 2;
}
else if (op == '*' || op == '/') {
priority = 4;
}
return priority;
}
//中缀表达式转成后缀表达式
template<class T>
void Calculator<T>::postfix(string mid_str) {
SeqStack<char> s1(100); //转换时操作符的辅助栈
//开始
s1.Push('#');
int j = 0;
for (int i = 0; i <(mid_str.size()); i++) {
if (mid_str[i] >= '0' && mid_str[i] <= '9') {
RPN_ch[j++]= mid_str[i];
}
else { //如果不是0~9操作数
int op_icp = icp(mid_str[i]);
if (isp(s1.getTop()) > op_icp) { //拿操作符辅助栈栈顶元素来与之比较
RPN_ch[j++] = s1.getTop();//因为一直是操作完自加j++,所以最后直接给[j]上的赋‘=’就好
s1.Pop();
s1.Push(mid_str[i]);
}
else if (isp(s1.getTop()) < op_icp) {
s1.Push(mid_str[i]);
}
else if (isp(s1.getTop()) == op_icp) {
s1.Pop();
}
}
}
//将余下操作符栈中元素放入RPN数组
while (!s1.IsEmpty()) {
if (s1.getTop() != '#') {
RPN_ch[j++]= s1.getTop();
s1.Pop();
}
else {
s1.Pop();
}
}
RPN_ch[j] = '=';
cout << "转化后的后缀表达式为:";
for (int k = 0; k <= j; k++) {
cout << RPN_ch[k];
}cout << endl;
}
main.cpp
#include "SeqStack.h"
#include "Calculate.h"
#include <string>
#include <iostream>
using namespace std;
/*
* 测试样例:
* 2
* 10
* 5*9+3-1
* 7+2*5
*/
void main()
{
int i;
cout << "请输入要计算的表达式行数:" << endl;
cin >> i;
cout << "请输入存放表达式的顺序栈最大容量:" << endl;
int sz; cin >> sz;
Calculator<double> newCal(sz);
string mid_str;
for(int j=0;j<i;j++)
{
cout << "请输入第"<<j+1<<"条中缀算术表达式:" << endl;
cin >> mid_str;
newCal.postfix(mid_str); //输入中缀并将将中缀转换成后缀
newCal.Run();
}
return;
}
可以直接跑,但也可能还有问题,欢迎建议。