************************************************** ************************************************** *****
O autor deste artigo é Noah Lazy Yangyang, um colega de classe do MF22, HKUST, para fornecer uma ideia de lição de casa, por favor, não copie diretamente! ! ! Vamos aprender juntos~
************************************************** ************************************************** ******
Índice
2.1 Descrição da estrutura de dados
2.2 Descrição da estrutura do programa
4. Análise espaço-temporal do algoritmo
5. Resultados e análises dos testes
Noah_Cal_Expression_With_Stack.h
1. Descrição do problema
1.1 Funções básicas
1. Cálculo polonês
+ 2 * 3 - 5 1 = 2 + 3 * (5 - 1) = 14 (11 pontos)
+ + 2 * 3 - 7 4/8 4=2+3*(7-4)+8/4=13(12 pontos)
2. Cálculo polonês reverso
2 3 5 1 - * += 2 + 3 * (5 - 1)=14 (11 pontos)
9 3 1 – 3* + 10 2 / +=9+(3-1)*3+10/2=20(12 pontos)
3. Cálculo do infixo
(1) 4 + 2 * 3 – 10/5 resultado do cálculo, deve produzir 8 (12 pontos);
(2)(4+2)*3 – 10 / 5 O resultado do cálculo deve produzir 16 (12 pontos);
1.2 Robustez
- O programa tem certo tratamento para exceções, como entrada ilegal, etc.
Por exemplo:
A expressão de entrada contém caracteres inválidos, (2 pontos)
Por exemplo: + 2 A, 2 3 A -, 4 + a
- O número de operandos e operadores na expressão de entrada não corresponde (mais operandos ou mais operadores) (4 pontos)
Tais como: + 2 2 2 , 2 2 2 + , 2 + 2 2 , + + 2 2 , 2 2 + +, 2 + + 2
- A entrada ilegal, como o emparelhamento, não pode ser concluída inserindo colchetes de expressão. (4 pontos)
Tal como (4 + 2 * 3, 4 + 2) * 3.
1.3 Normativa
- comentário de código
- modularização do programa
- Interação amigável humano-computador
2. Descrição do algoritmo
2.1 Descrição da estrutura de dados
A principal estrutura de dados utilizada no programa é a pilha sequencial.
Explicação das principais variáveis:
variável |
tipo |
ilustrar |
sq_stack |
estrutura |
A estrutura da pilha |
*base |
O ponteiro para o elemento inferior da pilha |
Usado para acessar o elemento inferior da pilha, controlar o armazenamento da pilha, calcular o número de elementos na estação, etc. |
*principal |
ponteiro para o elemento superior da pilha |
Usado para acessar o elemento superior da pilha, controlar o armazenamento da pilha, calcular o número de elementos na estação, etc. |
Tamanho da pilha |
int |
O tamanho do espaço de memória da pilha sequencial (o número de elementos que podem ser armazenados) |
expressão |
corda |
precisa avaliar a expressão |
STACK_INIT_SIZE |
definição de macro |
Inicializar o tamanho do espaço de armazenamento |
STACK_INCREMENT_SIZE |
definição de macro |
Tamanho do incremento de alocação de armazenamento |
STK_Tipo de item |
definição de macro |
O tipo de dados dos elementos na pilha |
2.2 Descrição da estrutura do programa
O programa inclui principalmente Noah_stack.h, Noah_expression_normaltoRPN.h, arquivo de cabeçalho Noah_Cal_Expression_With_Stack.h e arquivo principal main.cpp, onde Noah_stack.h é o arquivo de cabeçalho do código de implementação da estrutura de dados da pilha e Noah_expression_normaltoRPN.h é para converter a expressão infixa para o arquivo de cabeçalho de coleta de código de fórmula de expressão de sufixo (polonês reverso), Noah_Cal_Expression_With_Stack.h é o arquivo de cabeçalho de coleta de código da função de cálculo de diferentes expressões realizadas pela estrutura de dados da pilha de chamadas e código de conversão de expressão, main.cpp implementa principalmente o menu e interface de função Interação e chamadas para funções em arquivos de cabeçalho. Sua estrutura específica é mostrada na figura abaixo.
3. Análise de depuração
Função de depuração um: calculadora de expressão polonesa
Avalie as expressões polonesas
Seleção de dados de teste:
- + 2 * 3 - 5 1 = 2 + 3 * (5 - 1) = 14 (11 pontos)
- + + 2 * 3 - 7 4/8 4=2+3*(7-4)+8/4=13(12 pontos)
Problemas e soluções:
- Como a entrada io obtém um tipo de dados string, é necessário reconhecer símbolos e números, mas ao reconhecer números com dezenas ou dígitos maiores, eles não são reconhecidos como um número no início, mas são reconhecidos como números múltiplos. , a solução é adicionar o código de controle de julgamento correspondente para resolver este problema.
Função de depuração dois: calculadora de expressão polonesa inversa
Calcula a expressão polonesa reversa
Seleção de dados de teste:
- 2 3 5 1 - * += 2 + 3 * (5 - 1)=14 (11 pontos)
- 9 3 1 – 3 * + 10 2 / +=9+(3-1)*3+10/2=20(12 pontos)
Problemas e soluções:
- O código no início não distinguia se "10" é um número 1, um número 0 ou um número 10. Para resolver esse problema, é necessário adicionar um espaço entre cada número e o operador ao restringir a entrada.
Função de depuração três: calculadora de expressão infixa
Avaliar expressões infixas
Seleção de dados de teste:
- 4 + 2 * 3 – 10/5 resultado do cálculo, deve produzir 8 (12 pontos);
- (4+2)*3 – 10/5 resultado do cálculo, deve produzir 16 (12 pontos);
Problemas e soluções:
nenhum
Função de depuração quatro: teste de robustez
Seleção de dados de teste:
- 1 + ( 5 * 6 – 10
- um, um + 5
- 2 3 A –
- + + 2 2
- 4 + 2)* 3
Problemas e soluções:
nenhum
4. Análise espaço-temporal do algoritmo
(1)STK_Elemtype Polish_type_calculate(expressão de string)
Complexidade de tempo: O(n)
Complexidade do espaço: O(n)
(2)STK_Elemtype Inverse_Polish_type_calculate(expressão de string)
Complexidade de tempo: O(n)
Complexidade do espaço: O(n)
(3)STK_Elemtype Normal_type_calculate(expressão de string)
Complexidade de tempo: O(n)
Complexidade do espaço: O(n)
5. Resultados e análises dos testes
Função de teste um: calculadora de expressão polonesa
caso de teste |
resultado |
analisar |
+ 2 * 3 - 5 1 |
|
√, o cálculo polonês está correto |
+ + 2 * 3 - 7 4/8 4 |
|
√ |
Função de depuração dois: calculadora de expressão polonesa inversa
caso de teste |
resultado |
analisar |
2 3 5 1 - * + |
|
√, a fórmula polonesa reversa é calculada corretamente |
9 3 1 – 3 * + 10 2 / + |
|
√ |
Função de teste três: calculadora de expressão infixa
caso de teste |
resultado |
analisar |
4 + 2 * 3 – 10/5 |
|
√, a expressão infixa é calculada corretamente |
(4 + 2) * 3 – 10/5 |
|
√ |
Função de depuração quatro: teste de robustez
caso de teste |
resultado |
analisar |
1 + ( 5 * 6 – 10 |
|
√ |
um, um + 5 |
|
√ |
2 3 A – |
|
√ |
4 + 2) * 3 |
|
√ |
+ + 2 2 |
|
√ |
apêndice de código
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);
}