****************************************************** ****************************************************** *****
L'auteur de cet article est Noah Lazy Yangyang, un camarade de classe de MF22, HKUST, pour vous donner une idée de devoir, merci de ne pas copier directement ! ! ! Apprenons ensemble~
****************************************************** ****************************************************** ******
Table des matières
2. Description de l'algorithme
2.1 Description de la structure des données
2.2 Description de la structure du programme
4. Analyse spatio-temporelle de l'algorithme
5. Résultats des tests et analyse
Noah_Cal_Expression_With_Stack.h
1. Description du problème
1.1 Fonctions de base
1. Calcul polonais
+ 2 * 3 - 5 1 = 2 + 3 * (5 - 1) = 14 (11 points)
+ + 2 * 3 - 7 4 / 8 4=2+3*(7-4)+8/4=13(12 points)
2. Calcul polonais inversé
2 3 5 1 - * += 2 + 3 * (5 - 1)=14 (11 points)
9 3 1 – 3* + 10 2 / +=9+(3-1)*3+10/2=20(12 points)
3. Calcul de l'infixe
(1) résultat du calcul 4 + 2 * 3 – 10 / 5, devrait produire 8 (12 points);
(2)(4+2)*3 – 10 / 5 Le résultat du calcul devrait donner 16 (12 points) ;
1.2 Robustesse
- Le programme a une certaine gestion des exceptions, telles que les entrées illégales, etc.
Par exemple:
L'expression d'entrée contient des caractères illégaux, (2 points)
Par exemple : + 2 A, 2 3 A -, 4 + a
- Le nombre d'opérandes et d'opérateurs dans l'expression d'entrée ne correspond pas (plus d'opérandes ou plus d'opérateurs) (4 points)
Tels que : + 2 2 2 , 2 2 2 + , 2 + 2 2 , + + 2 2 , 2 2 + +, 2 + + 2
- Une entrée illégale telle que l'appariement ne peut pas être complétée en saisissant des parenthèses d'expression. (4 points)
Comme (4 + 2 * 3, 4 + 2) * 3.
1.3 Normatif
- commentaire de code
- modularisation du programme
- Interaction amicale entre l'homme et l'ordinateur
2. Description de l'algorithme
2.1 Description de la structure des données
La structure de données principale utilisée dans le programme est la pile séquentielle.
Explication des principales variables :
variable |
taper |
illustrer |
sq_stack |
structure |
La structure de la pile |
*base |
Le pointeur vers l'élément inférieur de la pile |
Permet d'accéder à l'élément du bas de la pile, de contrôler le stockage de la pile, de calculer le nombre d'éléments dans la station, etc. |
*haut |
pointeur vers l'élément supérieur de la pile |
Permet d'accéder à l'élément supérieur de la pile, de contrôler le stockage de la pile, de calculer le nombre d'éléments dans la station, etc. |
taille de la pile |
entier |
La taille de l'espace mémoire de la pile séquentielle (le nombre d'éléments pouvant être stockés) |
expression |
chaîne |
doit évaluer l'expression |
STACK_INIT_SIZE |
macro définition |
Initialiser la taille de l'espace de stockage |
STACK_INCREMENT_SIZE |
macro définition |
Taille d'incrément d'allocation de stockage |
STK_Type d'élément |
macro définition |
Le type de données des éléments de la pile |
2.2 Description de la structure du programme
Le programme comprend principalement Noah_stack.h, Noah_expression_normaltoRPN.h, le fichier d'en-tête Noah_Cal_Expression_With_Stack.h et le fichier principal main.cpp, où Noah_stack.h est le fichier d'en-tête de code d'implémentation de la structure de données de la pile, et Noah_expression_normaltoRPN.h doit convertir l'expression infixe au fichier d'en-tête de collection de code de formule (polonais inversé) d'expression de suffixe, Noah_Cal_Expression_With_Stack.h est le fichier d'en-tête de collection de code de la fonction de calcul de différentes expressions réalisées par la structure de données de la pile d'appels et le code de conversion d'expression, main.cpp implémente principalement le menu et interface de fonction Interaction et appels aux fonctions dans les fichiers d'en-tête. Sa structure spécifique est illustrée dans la figure ci-dessous.
3. Analyse de débogage
Fonction de débogage 1 : calculateur d'expression polonaise
Évaluer les expressions polonaises
Sélection des données de test :
- + 2 * 3 - 5 1 = 2 + 3 * (5 - 1) = 14 (11 points)
- + + 2 * 3 - 7 4 / 8 4=2+3*(7-4)+8/4=13(12 points)
Problèmes et solutions :
- Étant donné que l'entrée io obtient un type de données de chaîne, il est nécessaire de reconnaître les symboles et les nombres, mais lors de la reconnaissance de nombres avec des dizaines ou des chiffres supérieurs, ils ne sont pas reconnus comme un nombre au début, mais sont reconnus comme des nombres multiples. , la solution est d'ajouter le code de contrôle de jugement correspondant pour résoudre ce problème.
Fonction de débogage deux : calculatrice d'expression polonaise inverse
Calcule l'expression polonaise inverse
Sélection des données de test :
- 2 3 5 1 - * += 2 + 3 * (5 - 1)=14 (11 points)
- 9 3 1 – 3 * + 10 2 / +=9+(3-1)*3+10/2=20(12 points)
Problèmes et solutions :
- Le code au début ne distinguait pas si "10" est un nombre 1, un nombre 0 ou un nombre 10. Pour résoudre ce problème, un espace doit être ajouté entre chaque nombre et l'opérateur lors de la restriction de l'entrée.
Fonction de débogage trois : calculatrice d'expression infixe
Évaluer les expressions infixes
Sélection des données de test :
- 4 + 2 * 3 – 10/5 résultat du calcul, devrait sortir 8 (12 points) ;
- (4+2)*3 – 10/5 résultat du calcul, devrait produire 16 (12 points) ;
Problèmes et solutions :
aucun
Fonction de débogage quatre : test de robustesse
Sélection des données de test :
- 1 + ( 5 * 6 – 10
- un , un + 5
- 2 3 A –
- + + 2 2
- 4 + 2)* 3
Problèmes et solutions :
aucun
4. Analyse spatio-temporelle de l'algorithme
(1)STK_Elemtype Polish_type_calculate(expression de chaîne)
Complexité temporelle : O(n)
Complexité spatiale : O(n)
(2) STK_Elemtype Inverse_Polish_type_calculate (expression de chaîne)
Complexité temporelle : O(n)
Complexité spatiale : O(n)
(3)STK_Elemtype Normal_type_calculate(expression de chaîne)
Complexité temporelle : O(n)
Complexité spatiale : O(n)
5. Résultats des tests et analyse
Fonction de test 1 : calculateur d'expression polonaise
cas de test |
résultat |
analyser |
+ 2 * 3 - 5 1 |
|
√, le calcul polonais est correct |
+ + 2 * 3 - 7 4 / 8 4 |
|
√ |
Fonction de débogage deux : calculatrice d'expression polonaise inverse
cas de test |
résultat |
analyser |
2 3 5 1 - * + |
|
√, la formule polonaise inverse est calculée correctement |
9 3 1 – 3 * + 10 2 / + |
|
√ |
Fonction de test trois : calculatrice d'expression infixe
cas de test |
résultat |
analyser |
4 + 2 * 3 – 10 / 5 |
|
√, l'expression infixe est calculée correctement |
( 4 + 2) * 3 – 10 / 5 |
|
√ |
Fonction de débogage quatre : test de robustesse
cas de test |
résultat |
analyser |
1 + ( 5 * 6 – 10 |
|
√ |
un , un + 5 |
|
√ |
2 3 A – |
|
√ |
4 + 2) * 3 |
|
√ |
+ + 2 2 |
|
√ |
annexe du code
Noah_stack.h
#ifndef NOAH_STACK_H_INCLUDED
#define NOAH_STACK_H_INCLUDED
#include <stdlib.h>
#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;//空
else
return 0;//非空
}
//判断链表是否存满
int isStackfull(sq_stack s){
if(s.top - s.base >=s.stack_size)
return 1;//存满
else
return 0;//没有存满
}
//取栈顶元素
STK_Elemtype GetTop(sq_stack s){
//首先判断元素是否为空
if(isStackempty(s)){
cout << "The stack is Empty, return -1." << endl;
return STK_Elemtype(-1);
}
else
return *(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<len_Stack(s);i++)
printf("%.2f ",*(s.base+i));
}
#endif // NOAH_STACK_H_INCLUDED
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 <string>
#include <sstream>
#include <cmath>
#include <iostream>
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:"<<endl;
cin.ignore();
cin.getline(expression_chars,256);
expression = expression_chars;
legal = check_expression(expression);
if(!legal){
cout<<"Expression illegal, please input again."<<endl;
//char expression_chars[256] = "";
}
}
return expression;
}
//判断表达式是否合法,合法返回1,不合法返回0
int check_expression(string expression){
//三种不合法的方式
int expression_error_illegal_char = 0;
int expression_error_unaligment_numberandoperation = 0;
int expression_error_unaligment_bracket = 0;
//中间控制变量
int operands_num = 0;
int operation_num = 0;
int bracket_left = 0;
int bracket_right = 0;
string temp = "";
//按字符判断,循环
for (decltype(expression.size()) index = 0; index != expression.size(); index++){
char x = expression[index];
//cout<<x<<endl;
if(temp.size()>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++;
}
else
expression_error_illegal_char = 1;//有非法字符
//cout<<x<<operands_num<<operation_num<<bracket_left<<bracket_right<<endl;
}
if(operands_num!=(operation_num+1))
expression_error_unaligment_numberandoperation = 1;
if(bracket_left!=bracket_right)
expression_error_unaligment_bracket = 1;
//检查结果输出
if(expression_error_illegal_char||expression_error_unaligment_bracket||expression_error_unaligment_numberandoperation){
cout<<expression<<" "<<"is illegal!"<<endl;
if(expression_error_illegal_char)
cout<<"The input expression has an invalid character."<<endl;
if(expression_error_unaligment_numberandoperation)
cout<<"The input expression operands do not match the number of operators."<<endl;
if(expression_error_unaligment_bracket)
cout<<"The expression brackets are not as paired."<<endl;
return 0;//expression非法
}
return 1;//expression合法
}
//计算波兰式
STK_Elemtype Polish_type_calculate(string expression){
sq_stack s;
initStack(s);
//逆序遍历表达式字符串
string temp = "";
for (decltype(expression.size()) index = expression.size()-1; index != -1; index--){
char x = expression[index];
if(temp.size()>0 && x==' '){
push(s,stof(temp));
temp = "";
}
/*
cout<<x<<" "<<"stack:";
Display_Stack(s);
cout<<endl;
*/
if(x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='^'){
switch(x){
case('+'):
push(s,pop(s)+pop(s));break;
case('-'):
push(s,(-pop(s)+pop(s)));break;
case('*'):
push(s,pop(s)*pop(s));break;
case('/'):
push(s,pop(s)/pop(s));break;
case('%'):
{
int temp1 = int(pop(s));
int temp2 = int(pop(s));
push(s,temp1%temp2);break;
}
case('^'):
{
float temp1 = pop(s);
float temp2 = pop(s);
push(s,pow(temp1,temp2));break;
}
}
}
else if(x>='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<<x<<" "<<"stack:";
Display_Stack(s);
cout<<endl;
*/
if(x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='^'){
switch(x){
case('+'):
push(s,pop(s)+pop(s));break;
case('-'):
push(s,(0-pop(s)+pop(s)));break;
case('*'):
push(s,pop(s)*pop(s));break;
case('/'):
push(s,1/pop(s)*pop(s));break;
case('%'):
{
int temp1 = int(pop(s));
int temp2 = int(pop(s));
push(s,temp2%temp1);break;
}
case('^'):
{
float temp1 = pop(s);
float temp2 = pop(s);
push(s,pow(temp2,temp1));break;
}
}
}
else if(x>='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 <iostream>
#include <cstring>
#include <stack>
#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<char> s;
int i;
string temp = "";
for(i = 0; i < str.size(); i ++ )
{
//cout<<str[i]<<endl;
if(str[i]==' '){
//cout<<temp<<endl;
if(temp.size()>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 <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#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);
}