关于“计算题”程序的分析和总结
这次计算题程序已收官完成,再次进行分析和总结。
一、设计思路
1. 从txt读取算式。
2. 将算式由中缀转后缀。
3. 计算后缀算式并与用户输入答案进行比较,答案正确提示正确,答案错误提示错误并输出正确的答案。与此同时,统计用户正确与错误的次数以及题目的总数量。
4. 重复,直到算式全部计算完成,输出统计的正确错误数和题目的总数量。
二、具体实现
本程序运用了面向对象的设计思路。经过资料搜索,我发现有很多参考的程序。它们已经实现了中缀转后缀并输出正确结果并统计正误的功能,但无法计算分数。因此,我在此基础上进行了改进,增加了一个Fraction类。其把所有的整数都转换成了分数形式,并且重载了所有的运算符。之后,在重用的程序中把所有的定义的变量都定义为Fraction类型的就可以了。
以下是新增的Fraction类。
#pragma once #include <iostream> using namespace std; class Fraction { public: Fraction(); Fraction(int n); Fraction(int n, int d); ~Fraction(); int numerator; int denominator; Fraction operator + (Fraction f); Fraction operator - (Fraction f); Fraction operator * (Fraction f); Fraction operator / (Fraction f); bool operator == (Fraction f); friend istream &operator >> (istream &in, Fraction &f); friend ostream &operator << (ostream &out, Fraction &f); void reduction(); int get_gcd(int a, int b); };
#include "stdafx.h" #include "Fraction.h" Fraction::Fraction() { } Fraction::Fraction(int n) :numerator(n), denominator(1) { } Fraction::Fraction(int n, int d) : numerator(n), denominator(d) { } Fraction::~Fraction() { } Fraction Fraction::operator + (Fraction f) { return Fraction(numerator * f.denominator + denominator * f.numerator, denominator * f.denominator); } Fraction Fraction::operator - (Fraction f) { return Fraction(numerator * f.denominator - denominator * f.numerator, denominator * f.denominator); } Fraction Fraction::operator * (Fraction f) { return Fraction(numerator * f.numerator, denominator * f.denominator); } Fraction Fraction::operator / (Fraction f) { return Fraction(numerator * f.denominator, denominator * f.numerator); } bool Fraction::operator == (Fraction f) { return numerator == f.numerator && denominator == f.denominator; } istream& operator >> (istream &in, Fraction &f) { in >> f.numerator; f.denominator = 1; char c; in.get(c); if (c != '\n') { in >> f.denominator; } return in; } ostream& operator << (ostream &out, Fraction &f) { f.reduction(); if (f.denominator == 1) out << f.numerator; else out << f.numerator << "/" << f.denominator; return out; } void Fraction::reduction() { int gcd = get_gcd(numerator, denominator); numerator = numerator / gcd; denominator = denominator / gcd; if (denominator < 0) { numerator = -numerator; denominator = -denominator; } } int Fraction::get_gcd(int a, int b) { if (b == 0) return a; return get_gcd(b, a%b); }
以下是网上参考的只能进行整数运算的程序的改进。
#pragma once #include "Fraction.h" class Expression { public: Fraction Operand; char Operator = NULL; }; #include "stdafx.h" #include "Expression.h" ///////////////////////////////////////////////////////////////////////// #pragma once #include "Expression.h" #include <stack> #include <fstream> class Calculator { private: stack<char> is; stack<Fraction> ps; Expression InfixExp[100]; Expression PostfixExp[100]; int il; int pl; bool GetInfixExp(); bool Transform(); bool GetTwoOperands(Fraction &opd1, Fraction &opd2); bool Compute(char op); ifstream ifs, ifs_line; public: Calculator(); ~Calculator(); void Run(); }; #include "stdafx.h" #include "Calculator.h" Calculator::Calculator() { Run(); } Calculator::~Calculator() { } bool Calculator::GetInfixExp() { char c; int newOperand; bool lastExpIsNum = false; bool nextNumAddMinus = false; char printExp[128]; ifs_line.getline(printExp, 128); cout << printExp << " "; while (ifs >> c, c != '=') { switch (c) { case '-': if (lastExpIsNum) { InfixExp[il].Operator = c; } else { nextNumAddMinus = true; il--; } lastExpIsNum = false; break; case '+': case '*': case '/': case '(': InfixExp[il].Operator = c; lastExpIsNum = false; break; case ')': InfixExp[il].Operator = c; lastExpIsNum = true; break; default: if (c >= '0' && c <= '9') { ifs.putback(c); ifs >> newOperand; newOperand = nextNumAddMinus ? -newOperand : newOperand; nextNumAddMinus = false; InfixExp[il].Operand = Fraction(newOperand); } else { return false; } lastExpIsNum = true; break; } il++; } return true; } bool Calculator::Transform() { bool flag; for (int i = 0; i < il; i++) { if (InfixExp[i].Operator == NULL) { PostfixExp[pl].Operand = InfixExp[i].Operand; pl++; } else if (InfixExp[i].Operator == '(') { is.push('('); } else if (InfixExp[i].Operator == ')') { if (is.empty()) { return false; } else { flag = false; while (!is.empty()) { if (is.top() != '(') { PostfixExp[pl].Operator = is.top(); is.pop(); pl++; } else { flag = true; is.pop(); break; } } if (is.empty() && !flag) { return false; } } } else { while ( !is.empty() && is.top() != '(' && !((is.top() == '+' || is.top() == '-') && (InfixExp[i].Operator == '*' || InfixExp[i].Operator == '/')) ) { PostfixExp[pl].Operator = is.top(); is.pop(); pl++; } is.push(InfixExp[i].Operator); } } while (!is.empty()) { if (is.top() == '(') { return false; } else { PostfixExp[pl].Operator = is.top(); is.pop(); pl++; } } return true; } bool Calculator::GetTwoOperands(Fraction& opd1, Fraction& opd2) { if (ps.empty()) return false; opd1 = ps.top(); ps.pop(); if (ps.empty()) return false; opd2 = ps.top(); ps.pop(); return true; } bool Calculator::Compute(char op) { bool result; Fraction operand1, operand2; result = GetTwoOperands(operand1, operand2); if (result) { switch (op) { case '+': ps.push(operand2 + operand1); break; case '-': ps.push(operand2 - operand1); break; case '*': ps.push(operand2 * operand1); break; case '/': if (operand1.numerator == 0) { cout << "除数存在0,错误!" << endl; return false; } else { ps.push(operand2 / operand1); } break; } } return true; } void Calculator::Run() { ifs = ifstream("Expressions.txt"); ifs_line = ifstream("Expressions.txt"); Fraction correct_answer, user_answer; int correct_num = 0, wrong_num = 0; // 输入中缀表达式 cout << "请计算下列算式:" << endl; while (!ifs_line.eof()) { il = 0; pl = 0; while (!is.empty()) is.pop(); while (!ps.empty()) ps.pop(); for (int i = 0; i < 100; i++) { InfixExp[i] = PostfixExp[i] = Expression(); } if (GetInfixExp() && Transform()) { for (int i = 0; i < pl; i++) { if (PostfixExp[i].Operator == NULL) ps.push(PostfixExp[i].Operand); else { if (!Compute(PostfixExp[i].Operator)) return; } } correct_answer = ps.top(); } else { cout << "算式格式错误" << endl; return; } cin >> user_answer; user_answer.reduction(), correct_answer.reduction(); if (user_answer == correct_answer) { correct_num++; cout << "正确" << endl; } else { wrong_num++; cout << "错误,正确答案是" << correct_answer << endl; } } cout << "--------------------------" << endl; cout << "共" << correct_num + wrong_num << "题,"; cout << "正确" << correct_num << "道,错误" << wrong_num << "道" << endl; }
三、项目总结
这次项目,对我改进程序的能力有了提升。每个程序并不是一定要从零开始。我们可以利用他人的的思路和成果,再次基础上进行改进。同时,我们也应多和他人进行交流,因为这样可以更方便地获取新鲜高端的思路,对项目的完成有所广益。