课程第六次作业

非 Y 不嫁゛ 提交于 2019-12-23 02:17:43

课程第六次作业

题目要求;

  • 本次作业要求将四则运算的核心部分采取栈的知识进行解决。即表达式生成的合法性检验、表达式结果计算。
  • 学习C++界面编程,可以学QT、MFC或者VS,选择其一即可,用博客记录学习到的知识以及心得体会。

    界面的不足之处:

界面没有实现可以下一题的操作,没有锁定算式不能被操作,所以容易被误操作。使输出答案。

学习链接

git链接

界面展示:


代码展示:

void CMFCApplication2Dlg::OnBnClickedButton1()
{
    UpdateData();
    //expression ;窗口添加的变量
    Problem p; 
    tmp = p.generateExpression();
    expression = tmp.c_str();//将string转变为Cstring    
    UpdateData(false);
}


void CMFCApplication2Dlg::OnBnClickedButton2()
{
    UpdateData();
    Problem p;
    rightanswer = p.calculateResult(tmp);//tmp为全局变量实现题目的传入
    if (answer == rightanswer)//answer为用户在界面输入的答案(窗口添加的变量),rightanswer为正确的答案
    {
        correctnum++;//给窗口添加的变量(正确的题目个数)
    }
    else
        wrongnum++;//错误的答案
    UpdateData(false);
}

核心算法流程图展示:

生成算法:

计算算法:

生成算式部分

//生成算式部分----------------------------------------------------------------------
    int Randomvalue::randomNumber()//用于随机生成数字
    {
        return num[rand() % num.size()];
    }
    char Randomvalue::randomOperation()//用于随机生成运算符
    {
        return sign[rand() % sign.size()];
    }

    template<typename T>//模板
    string CreatExpresstion::Tostring(T i)
    {
        stringstream ss;
        string s;
        ss << i;
        ss >> s;
        return s;
    }

    void CreatExpresstion::generateExpression()//用于生成运算式
    {
        expression = Tostring(R.randomNumber()) + Tostring(R.randomOperation()) + Tostring(R.randomNumber());//利用Tostring函数
        int len = rand() % 5 + 2;
        for (int i = 0; i < len; i++)//add '(' and ')'
        {
            int rdnum = rand() % 10 + 1;
            if (rdnum<2)// 加左边 加括号
            {
                expression = Tostring(R.randomNumber()) + Tostring(R.randomOperation()) + "(" + Tostring(expression) + ")";//连接
            }
            else if (rdnum>8)// 加右边 加括号
            {
                expression = "(" + Tostring(expression) + ")" + Tostring(R.randomOperation()) + Tostring(R.randomNumber());
            }
            else if (rdnum<4)// 加左边 不加括号
            {
                expression = Tostring(R.randomNumber()) + Tostring(R.randomOperation()) + Tostring(expression);
            }
            else if (rdnum>6)// 加右边 不加括号
            {
                expression = Tostring(expression) + Tostring(R.randomOperation()) + Tostring(R.randomNumber());
            }
            // 不加
        }
        cout << expression << " = ";//输出算式
        F.writeFile(out_file_name,expression);//写入文件中
        F.writeFile(out_file_name," = ");
        //myfile << expression << " = ";
        answer = calculateResult();
    }

算式计算部分:

unordered_map< char, unordered_map < char, char > > Priorities;

void InitPriorities()//优先级代码
    {
        Priorities['+']['-'] = '>';
        Priorities['+']['+'] = '>';
        Priorities['+']['*'] = '<';
        Priorities['+']['/'] = '<';
        Priorities['+']['('] = '<';
        Priorities['+'][')'] = '>';//右括号优先级最低

        Priorities['-']['-'] = '>';
        Priorities['-']['+'] = '>';
        Priorities['-']['*'] = '<';
        Priorities['-']['/'] = '<';
        Priorities['-']['('] = '<';
        Priorities['-'][')'] = '>';

        Priorities['*']['-'] = '>';
        Priorities['*']['+'] = '>';
        Priorities['*']['*'] = '>';
        Priorities['*']['/'] = '>';
        Priorities['*']['('] = '<';
        Priorities['*'][')'] = '>';

        Priorities['/']['-'] = '>';
        Priorities['/']['+'] = '>';
        Priorities['/']['*'] = '>';
        Priorities['/']['/'] = '>';
        Priorities['/']['('] = '<';
        Priorities['/'][')'] = '>';

        Priorities['(']['+'] = '<';
        Priorities['(']['-'] = '<';
        Priorities['(']['*'] = '<';
        Priorities['(']['/'] = '<';
        Priorities['(']['('] = '<';
        Priorities['('][')'] = '=';
    }
//算式计算部分----------------------------------------------------------------------
    float CreatExpresstion::calculateResult()
    {
        vector<float> Operands;
        vector<char> Operators;
        float OperandTemp = 0;
        char LastOperator = 0;

        for (int i = 0; i < expression.size(); i++)
        {
            char ch = expression[i];//获取分解算式
            if ('0' <= ch && ch <= '9')//如果为运算数
            {
                OperandTemp = OperandTemp * 10 + ch - '0';
            }
            else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')')
            {
                if (ch != '(' && LastOperator != ')')
                {
                    Operands.push_back(OperandTemp);//压入运算数栈中
                    OperandTemp = 0;
                }
                char Opt2 = ch;
                for (; Operators.size() > 0;)//不为空继续计算
                {
                    char Opt1 = Operators.back();
                    char CompareRet = Priorities[Opt1][Opt2];//利用运算符优先级
                    if (CompareRet == '>')//如果优先级为大于
                    {
                        float Operand2 = Operands.back();//获取运算数栈顶元素
                        Operands.pop_back();//冒掉栈顶元素
                        float Operand1 = Operands.back();//获取第二个运算数栈顶元素
                        Operands.pop_back();//冒掉运算数
                        Operators.pop_back();//冒掉运算符
                        float Ret = caculate(Operand1, Operand2, Opt1);//调用计算函数
                        Operands.push_back(Ret);//将计算结果压入栈中以便继续计算
                    }
                    else if (CompareRet == '<')//如果优先级为小于则跳过
                    {
                        break;
                    }
                    else if (CompareRet == '=')//如果优先级相等
                    {
                        Operators.pop_back();
                        break;
                    }
                }
                if (Opt2 != ')')
                {
                    Operators.push_back(Opt2);
                }
                LastOperator = Opt2;
            }
        }
        if (LastOperator != ')')
        {
            Operands.push_back(OperandTemp);
        }
        for (; Operators.size() > 0;)//如果运算符栈不为空继续
        {
            float Operand2 = Operands.back();
            Operands.pop_back();
            float Operand1 = Operands.back();
            Operands.pop_back();
            char Opt = Operators.back();
            Operators.pop_back();
            float Ret = caculate(Operand1, Operand2, Opt);
            Operands.push_back(Ret);
        }
        return (float)((int)(Operands.back() * 100)) / 100;//将计算结果返回为保留两位小数
    }

    float CreatExpresstion::caculate(float Operand1, float Operand2, char Operator)
    {
        if (Operator == '+') return Operand1 + Operand2;
        if (Operator == '-') return Operand1 - Operand2;
        if (Operator == '*') return Operand1 * Operand2;
        if (Operator == '/') return Operand1 / Operand2;
    }
    //----------------------------------------------------------------------------------

操作界面展示:

本次作业的心得:

本次作业实现了栈以及生成算式的核心算法,栈是一种重要的思想,曾经以为很难的计算过程可以利用栈来精巧的解决,而这些是想不到的,在查阅计算器计算过程中发现了这一点,在界面学习的过程中第一次觉得更像在写程序的感觉,界面使这一应用更趋向完整性、有使用价值,在今后的学习中会利用课余的时间学习更加高深精致的界面制作。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!