【数据结构】c++栈的应用:波兰式、逆波兰式和中缀表达式计算器
创始人
2024-01-31 07:57:52
0

 *********************************************************************************************************

本文作者科大MF22某班Noah懒羊羊同学,为大家提供一个作业思路,请勿直接copy!!!一起进步学习~

**********************************************************************************************************

目录

1.问题的描述

1.1基本功能

1.2健壮性

1.3 规范性

2.算法的描述

2.1数据结构的描述

2.2程序结构的描述

3.调试分析

4.算法的时空分析

5.测试结果及分析

代码附录

Noah_stack.h

Noah_Cal_Expression_With_Stack.h

Noah_expression_noemaltoRPN.h

Main.cpp


1.问题的描述

1.1基本功能

1.  波兰式计算

+ 2 * 3 - 5 1= 2 + 3 * (5 - 1)=14(11分)

+ + 2 * 3 - 7 4 / 8 4=2+3*(7-4)+8/4=13(12分)

2.  逆波兰式计算

2 3 5 1 - * += 2 + 3 * (5 - 1)=14(11分)

9 3 1 – 3* + 10  2 / +=9+(3-1)*3+10/2=20(12分)

                        

3.  中缀式计算

(1)4 + 2 * 3 – 10 / 5 计算结果,应输出8(12分);

(2)(4+2)*3 – 10 / 5 计算结果,应输出16(12分);

1.2健壮性

  1. 程序对异常有一定的处理,如非法输入等

例如:

输入表达式有非法字符,(2分)

如:+ 2 A 、 2 3 A - 、 4 + a

  1. 输入表达式操作数和运算符数目不匹配(操作数多或运算符多)(4分)

如:+ 2 2 2 、 2 2 2 + 、 2 + 2 2 、+ + 2 2 、2 2 + +、 2 + + 2

  1. 输入表达式括号无法完成配对等非法输入。(4分)

如( 4 + 2 * 3、4 + 2)* 3。

1.3 规范性

  1. 代码注释
  2. 程序模块化
  3. 人机交互友好

2.算法的描述

2.1数据结构的描述

程序中应用到的主要数据结构是顺序栈。

 

主要变量说明:

变量

类型

说明

sq_stack

结构体

栈的结构体

*base

栈的底部元素指针

用于访问栈的底部元素,控制栈的存储,计算站的元素个数等

*top

栈的顶部元素指针

用于访问栈的顶部元素,控制栈的存储,计算站的元素个数等

stack_size

int

顺序栈的内存空间大小(可存储的元素个数)

expression

string

需要计算表达式

STACK_INIT_SIZE

宏定义

初始化存储空间大小

STACK_INCREMENT_SIZE

宏定义

存储空间分配增量大小

STK_Elemtype

宏定义

栈中元素的数据类型

2.2程序结构的描述

        程序主要包含Noah_stack.h、Noah_expression_normaltoRPN.h、Noah_Cal_Expression_With_Stack.h头文件和main.cpp主文件,其中Noah_stack.h是栈数据结构的实现代码头文件,Noah_expression_normaltoRPN.h是将中缀表达式转为后缀表达式(逆波兰式)的代码集合头文件、Noah_Cal_Expression_With_Stack.h是调用栈数据结构和表达式转换代码实现的计算不同表达式的功能的代码集合头文件,main.cpp中主要实现菜单和功能界面的交互以及头文件中函数的调用。其具体结构如下图所示。

 

3.调试分析

调试功能一:Polish expression calculator

计算波兰式表达式

 

测试数据选择:

  1. + 2 * 3 - 5 1= 2 + 3 * (5 - 1)=14(11分)
  2. + + 2 * 3 - 7 4 / 8 4=2+3*(7-4)+8/4=13(12分)

问题及解决方法:

  1. 由于io输入获得的是字符串数据类型,因此需要进行符号和数字的识别,但在识别十位数或者位数更高的数字时一开始没有识别成一个数字,而是识别成了多个数字,解决方法是添加了相应的判断控制代码,解决这一问题。

调试功能二:Inverse Polish expression calculator

计算逆波兰式表达式

 

测试数据选择:

  1. 2 3 5 1 - * += 2 + 3 * (5 - 1)=14(11分)
  2. 9 3 1 – 3 * + 10  2 / +=9+(3-1)*3+10/2=20(12分)

问题及解决方法:

  1. 一开始的代码中没有区分“10”是数字1和数字0还是一个数字10,为解决这一问题,限制输入时每一个数字和运算符之间需要加一个空格。

调试功能三:Infix expression calculator

计算中缀表达式

 

测试数据选择:

  1. 4 + 2 * 3 – 10 / 5 计算结果,应输出8(12分);
  2. (4+2)*3 – 10 / 5 计算结果,应输出16(12分);

问题及解决方法:

调试功能四:稳健性测试

 

测试数据选择:

  1. 1 + ( 5 * 6 – 10
  2. a , a + 5
  3. 2 3 A –
  4. + + 2 2
  5. 4 + 2)* 3

问题及解决方法:

4.算法的时空分析

(1)STK_Elemtype Polish_type_calculate(string expression)

时间复杂度:O(n)

空间复杂度:O(n)

(2)STK_Elemtype Inverse_Polish_type_calculate(string expression)

时间复杂度:O(n)

空间复杂度:O(n)

(3)STK_Elemtype Normal_type_calculate(string expression)

时间复杂度:O(n)

空间复杂度:O(n)

5.测试结果及分析

测试功能一:Polish expression calculator

测试用例

结果

分析

+ 2 * 3 - 5 1

 

√,波兰式计算正确

+ + 2 * 3 - 7 4 / 8 4

 

调试功能二:Inverse Polish expression calculator

测试用例

结果

分析

2 3 5 1 - * +

 

√,逆波兰式计算正确

9 3 1 – 3 * + 10  2 / +

 

测试功能三:Infix expression calculator

测试用例

结果

分析

4 + 2 * 3 – 10 / 5

 

√,中缀表达式计算正确

( 4 + 2) * 3 – 10 / 5

 

调试功能四:健壮性测试

测试用例

结果

分析

1 + ( 5 * 6 – 10

 

a , a + 5

 

2 3 A –

 

4 + 2) * 3

 

+ + 2 2

 

代码附录

Noah_stack.h

#ifndef NOAH_STACK_H_INCLUDED
#define NOAH_STACK_H_INCLUDED
#include 
#define STACK_INIT_SIZE 100//初始化存储空间大小
#define STACK_INCREMENT_SIZE 10//存储空间分配增量大小
#define STK_Elemtype float
typedef struct{STK_Elemtype *base;STK_Elemtype *top;int stack_size;
}sq_stack;//初始化栈(顺序栈)
void initStack(sq_stack &s){s.base = (STK_Elemtype *)malloc(STACK_INIT_SIZE * sizeof(STK_Elemtype));/*if(!s.base)exit(overflow_error);//内存空间不足初始化失败,程序退出*/s.top = s.base;s.stack_size = STACK_INIT_SIZE;
}
//为顺序栈重新分配空间并将空间扩大incrementsize*sizeof(element)
void incrementStack(sq_stack &s,int incrementsize){s.base =(STK_Elemtype *)realloc(s.base,(s.stack_size + incrementsize)*sizeof(STK_Elemtype));/*if(!s.base)exit(overflow_error);//内存空间不足,增加size失败,程序退出*/s.top = s.base + s.stack_size;s.stack_size += incrementsize;
}
//判断链表是否为空
int isStackempty(sq_stack s){if(s.base==s.top)return 1;//空elsereturn 0;//非空
}
//判断链表是否存满
int isStackfull(sq_stack s){if(s.top - s.base >=s.stack_size)return 1;//存满elsereturn 0;//没有存满
}
//取栈顶元素
STK_Elemtype GetTop(sq_stack s){//首先判断元素是否为空if(isStackempty(s)){cout << "The stack is Empty, return -1." << endl;return STK_Elemtype(-1);}elsereturn *(s.top - 1);
}//入栈
void push(sq_stack &s,STK_Elemtype e){if(isStackfull(s))incrementStack(s,STACK_INCREMENT_SIZE);*s.top++ = e;
}//出栈
STK_Elemtype pop(sq_stack &s){if(isStackempty(s)){cout << "The stack is Empty, return -1." << endl;return STK_Elemtype(-1);}else//cout<<"pop:"<<*(s.top-1);return *--s.top;}
//返回链表中的元素个数
int len_Stack(sq_stack s){return s.top-s.base;
}//打印链表中所有元素
void Display_Stack(sq_stack s){if(isStackempty(s)){printf("The stack is Empty.");return ;}for(int i = 0 ; i

Noah_Cal_Expression_With_Stack.h

#ifndef NOAH_CAL_EXPRESSION_WITH_STACK_H_INCLUDED
#define NOAH_CAL_EXPRESSION_WITH_STACK_H_INCLUDED
#include "Noah_stack.h"
#include "Noah_expression_normaltoRPN.h"
#include 
#include 
#include 
#include 
using namespace std;string input_expression();
int check_expression(string expression);
STK_Elemtype Polish_type_calculate(string expression);
STK_Elemtype Inverse_Polish_type_calculate(string expression);
STK_Elemtype Normal_type_calculate(string expression);//输入一个表达式
string input_expression(){int legal = 0;char expression_chars[256];string expression;while(!legal){cout <<"Please input the expression:"<0 && x==' '){temp = "";operands_num++;}if(x=='('||x==')'||x==' '){if(x=='(')bracket_left++;else if(x == ')')bracket_right++;continue;}if(x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='^')operation_num++;else if(x>='0'&&x<='9'){temp +=x;if(index == expression.size()-1)operands_num++;}elseexpression_error_illegal_char = 1;//有非法字符//cout<0 && x==' '){push(s,stof(temp));temp = "";}/*cout<='0'&&x<='9'){temp = x + temp;if(index==0)push(s,stof(temp));}}return pop(s);
}//计算逆波兰式
STK_Elemtype Inverse_Polish_type_calculate(string expression){sq_stack s;initStack(s);//正序遍历表达式字符串string temp = "";for (decltype(expression.size()) index = 0; index != expression.size(); index++){char x = expression[index];if(temp.size()>0 && x==' '){push(s,stof(temp));temp = "";}/*cout<='0'&&x<='9'){temp = temp + x;if(index==expression.size()-1)push(s,stof(temp));}}return pop(s);
}//计算中缀表达式,先转为逆波兰式再计算逆波兰式
STK_Elemtype Normal_type_calculate(string expression){return Inverse_Polish_type_calculate(RPN(expression));
}#endif // NOAH_CAL_EXPRESSION_WITH_STACK_H_INCLUDED

Noah_expression_noemaltoRPN.h

#ifndef NOAH_EXPRESSION_NORMALTORPN_H_INCLUDED
#define NOAH_EXPRESSION_NORMALTORPN_H_INCLUDED
#include 
#include 
#include 
#include "Noah_stack.h"using namespace std;
int priority_func(char op);//判断运算符的优先级
int priority_func(char op)
{int priority;if(op == '*' || op == '/') priority = 2;if(op == '+' || op == '-') priority = 1;if(op == '(') priority = 0;return priority;
}//将中缀表达式转为逆波兰式
string RPN(string str)
{string str1="";stack s;int i;string temp = "";for(i = 0; i < str.size(); i ++ ){//cout<0){str1 = str1+ " " + temp;temp = "";}continue;}//是数字的情况下直接输出if(str[i] >= '0' && str[i] <= '9' ){temp = temp+string(1,str[i]);if(i==str.size()-1)str1 = str1+ " " + temp;}else //不是数字的情况分类讨论进行判断{//栈为空时直接入栈if(s.empty()) s.push(str[i]);//左括号入栈else if(str[i] == '(') s.push(str[i]);//如果是右括号,只要栈顶不是左括号,就弹出并输出else if(str[i] == ')'){while(s.top() != '('){str1 = str1+ " " + s.top();s.pop();}//弹出左括号,但不输出s.pop();}else{//栈顶元素的优先级大于等于当前的运算符,就将其输出while(priority_func(str[i]) <= priority_func(s.top())){str1 = str1+ " " + s.top();s.pop();//栈为空,停止if(s.empty()) break;}s.push(str[i]);}}}//最后,如果不为空,就把所以的元素全部弹出while(!s.empty()){str1 = str1+ " " + s.top();s.pop();}string str2 = str1.substr(1,str1.size());str1 = str2;return str1;
}#endif // NOAH_EXPRESSION_NORMALTORPN_H_INCLUDED

Main.cpp

#include 
using namespace std;
#include 
#include 
#include 
#include "Noah_Cal_Expression_With_Stack.h"
void Menue_gui();
void func1();
void func2();
void func3();int main()
{while(1){Menue_gui();int func;scanf("%d",&func);switch(func){case 0:exit(0);case 1:func1();break;case 2:func2();break;case 3:func3();break;default:printf("Input error! Please try again!");}printf("\n");system("pause");}return 0;
}//菜单界面
void Menue_gui(){system("cls");//清屏printf("****************Polish, inverse Polish, and infix expression calculators*********************\n");printf("*********************************************************************************************\n");printf("Menue:\n");printf("\nExit this program------------------------------------------------------0.\n");printf("\nPolish expression calculator-------------------------------------------1.\n");printf("\nReverse Polish expression calculator-----------------------------------2.\n");printf("\nInfix expression calculator--------------------------------------------3.\n");printf("\n**********************************************************************************************\n");printf("Choose the function you want to use(input number):\n");
}//功能1界面
void func1(){system("cls");//清屏printf("-----ENTER FUNCTION : Polish expression calculator--1.-----\n");printf("Input Polish expression(example:+ 2 * 3 - 5 1)\n");string polish_expression;polish_expression = input_expression();float reslut = float(Polish_type_calculate(polish_expression));printf("Result:%.2f",reslut);
}//功能2界面
void func2(){system("cls");//清屏printf("-----ENTER FUNCTION : Inverse Polish expression calculator--2-----.\n");printf("Input Inverse Polish expression(example:2 3 5 1 - * +)\n");string Inverse_polish_expression;Inverse_polish_expression = input_expression();float reslut = float(Inverse_Polish_type_calculate(Inverse_polish_expression));printf("Result:%.2f",reslut);
}//功能3界面
void func3(){system("cls");//清屏printf("-----ENTER FUNCTION : Infix expression calculator--3.-----\n");printf("Input Infix expression(example:4 + 2 * 3 – 10 / 5)\n");string Infix_expression;Infix_expression = input_expression();float reslut = float(Normal_type_calculate(Infix_expression));printf("Result:%.2f",reslut);
}

相关内容

热门资讯

技术创新+政策支持,北京青年用... 2025年,北京新能源汽车产业蓬勃发展,产量同比大幅增长,市场渗透率持续领先。在这股绿色浪潮中,北京...
网易云音乐前CEO朱一闻起诉老... 1月15日,天眼查App显示,近日,朱一闻、网易云音乐股份有限公司与杭州网易云音乐科技有限公司相关合...
政策红利持续释放,港股房地产板... 新京报贝壳财经讯(记者段文平)1月15日,港股房地产板块走强。据Wind数据显示,截至当天下午收盘,...
陕建股份(600248)披露公... 截至2026年1月15日收盘,陕建股份(600248)报收于3.59元,较前一交易日下跌0.28%,...
大婚被翻出谣言,霸王茶姬创始人... 1月15日消息,据企查查显示,北京互联网法院受理了霸王茶姬创始人张俊杰、北京茶姬餐饮管理有限公司与赵...
柳林法院:乘车起纠纷,调解化干... 近日,柳林县人民法院成功调解了一起因乘客殴打司机而引发的生命权、身体权、健康权纠纷。 2025年7月...
央行出台一批重磅政策,解读来了 1月15日,国新办就货币金融政策支持实体经济高质量发展成效举行新闻发布会。中国人民银行新闻发言人、副...
福建漳州20年酱油厂被指强拆,... 针对此事,张勇旗律师明确,行政机关拆除违法建筑需严格遵循法定流程。首先要确认具有执法权的行政机关是否...
一财社论:以制度完备助力市场行... 投资者信心比黄金还重要。 14日午间,经证监会批准,沪深北三家交易所发布通知,将投资者融资买入证券时...