zoukankan      html  css  js  c++  java
  • 关于“计算题”程序的分析和总结

    这次计算题程序已收官完成,再次进行分析和总结。

    一、设计思路

    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 != '
    ')
        {
            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;
    }

    三、项目总结

    这次项目,对我改进程序的能力有了提升。每个程序并不是一定要从零开始。我们可以利用他人的的思路和成果,再次基础上进行改进。同时,我们也应多和他人进行交流,因为这样可以更方便地获取新鲜高端的思路,对项目的完成有所广益。

  • 相关阅读:
    网站常见的反爬虫和应对方法 + [评论]
    斯坦福大学自然语言处理第一课——引言(Introduction)
    爬虫入门实战,知乎小爬虫
    使用情感分析技术做营销
    字符串匹配的KMP算法
    向Array中添加希尔排序
    向Array中添加二分插入排序
    向Array中添加插入排序
    开辟我的前端之旅!
    【apache】yum 安装Apache(Centos 6.5)
  • 原文地址:https://www.cnblogs.com/xDan/p/5295773.html
Copyright © 2011-2022 走看看