担任角色

在这次结对项目中,由于采用了我的个人项目作为参考,所以我继续担任后端开发的角色。

开发环境

前端采用Qt Creator4.13.2 (Community)

后端采用C++

如何复用个人项目

通过对结对项目需求的分析,需要实现的功能大致如下:

  1. 注册和登录

  2. 修改密码

  3. 生成题目

  4. 题目作答并统计结果

详细功能需求描述和设计框架见下文 “整体设计框架”。

复用的个人项目的工程框架如下

Headers
User.h
SystemPrompt.h
TreeNode.h
RandomizeTestPaper.h
Sources
main.cpp
User.cpp
SystemPrompt.cpp
TreeNode.cpp
RandomizeTestPaper.cpp

通过了解结对项目的功能需求,经过讨论,决定采用以下复用方式

  1. 复用个人项目中随机生成题目的部分,即 TreeNode 和 RandomizeTestPaper 这两部分。小学题目不需要更改,但初中题目中涉及复杂的平方根运算,高中题目的三角函数也都是与 π 无关的弧度角。当这些情况都合在一起的时候,除了利用库函数计算出小数结果(这样对计算机而言都是可行的,但是对用户的使用体验是极不友好的),难以表示表达式的结果,因此需要对这两个难度的题目进行调整,详见下文“表达式求值”部分。初高的题目调整后,在个人项目的基础上增加 “表达式求值” 功能即可。

  2. User 部分与结对项目需求中的 “注册和登录” 有一定的相关度,添加和完善一些功能即可复用。

  3. SystemPrompt 部分主要是用于输出一些系统提示,与结对项目需求基本无关,不考虑复用。

整体设计框架

在清楚如何复用对个人项目的情况下,经过讨论得出结对项目的大致设计框架

表达式求值

添加限制规则的目的:让题目的难度符合正常的小初高试卷难度``

为了避免了平方、开平方、三角函数运算产生的复杂浮点数中间结果对整个表达式求解产生的严重阻碍,我们对小初高运算进行了如下限制:

  1. 小学表达式不作任何改变。

  2. 初中表达式中,平方内的运算结果一定在[-100, 100]之间,避免计算大数的平方;开平方内的运算结果一定是[1, 400]之间的平方数,保证开平方的结果是整数。

  3. 高中表达式中,三角函数全都是与 π 有关的特殊角,计算结果一定是-1, -1/2, 0, 1/2, 1只中的一个。

如此限制,整个表达式的计算结果最多包含一位小数。

构造逆波兰式

问题描述:给出一个名为 infix 的中缀表达式,类型为 string 数组,数组中只包含整数和 "+", "-", "*", "/" , "(", ")". 返回它的逆波兰式,返回类型也是 string 数组。

算法描述:使用一个名为 RPN 的 string 数组存储结果,一个名为 ops 的 string 类型的栈辅助转化,规定 "(" 和 ")".的优先级为 0,"+" 和 "-" 的优先级为 1,"*" 和 "/" 的优先级为 2。

从左至右遍历 infix ,当前位置的字符串记为 str

  • 如果 str 是一个数字,直接加入 RPN. 判断下一个 str.
  • 否则是操作符,循环执行以下步骤。
    • 如果当前栈为空 或 str 是 "(" ,直接入栈,跳出当前循环, 判断下一个 str.
    • 否则比较 str 和栈顶操作符的优先级
      • 如果 str 的优先级高,直接入栈,跳出当前循环,判断下一个 str.
      • 否则 弹出栈顶,非 "(" 的元素全部加入 RPN,直至遇到 "(" 跳出当前循环,判断下一个 str.

遍历完毕后,把 ops 中剩余的元素依次放入 RPN 中即可得到逆波兰式。

参考代码

// 构建逆波兰式
vector<string> RandomizeTestPaper::BuildRPN(string expression)
{
vector<string> infixExpression = BuildInfixExpression(expression); // 中缀表达式
map<string, int> precedence = GetPrecedence(); // 优先级
vector<string> RPN; // 逆波兰式
stack<string> ops; // 用于存储操作符 int infixSize = infixExpression.size();
for (int i = 0; i < infixSize; i++)
{
string s = infixExpression.at(i);
// 是一个数字
if (precedence.find(s) == precedence.end())
{
RPN.push_back(s);
continue;
} // 是一个操作符
while (true)
{
// 空栈直接入栈
if (ops.empty())
{
ops.push(s);
break;
}
// 左括号 或 优先级比栈顶高 则入栈
map<string, int>::iterator it1 = precedence.find(s);
map<string, int>::iterator it2 = precedence.find(ops.top());
if (s == "(" || (it1->second > it2->second))
{
ops.push(s);
break;
}
// 优先级比栈顶低,要出栈了
string op = ops.top();
ops.pop();
// 左括号作为跳出循环的标志,其他运算符加入 RPN
if (op == "(")
{
break;
}
else
{
RPN.push_back(op);
}
}
}
// 剩余元素加入 RPN
while (!ops.empty())
{
RPN.push_back(ops.top());
ops.pop();
}
return RPN;
}

逆波兰式求值

问题描述:给出一个名为 RPN 的逆波兰表达式,类型为 string 数组,计算这个表达式的结果,返回类型为 int.

算法描述:借助一个名为 stk 的栈,类型为 int.

遍历 RPN 数组,记当前位置的字符串为 str

  • 如果 str 是一个数字,直接入栈,判断下一个 str.
  • 否则是一个操作符,依次从栈取出两个元素分别作为第个操作数和第个操作数,注意先二后一,作当前操作符的运算后,将结果重新入栈,判断下一个 str. 注意除法出现除以 0 要作特殊处理。

参考代码

// 计算逆波兰表达式
int RandomizeTestPaper::calculateRPN(string expression)
{
vector<string> RPN = BuildRPN(expression); // 逆波兰式
stack<int> stk;
int RPNsize = RPN.size();
int operand1 = 0, operand2 = 0;
for (int i = 0; i < RPNsize; i++)
{
if (RPN[i] == "+")
{
operand2 = stk.top();
stk.pop();
operand1 = stk.top();
stk.pop();
stk.push(operand1 + operand2);
}
else if (RPN[i] == "-")
{
operand2 = stk.top();
stk.pop();
operand1 = stk.top();
stk.pop();
stk.push(operand1 - operand2);
}
else if (RPN[i] == "*")
{
operand2 = stk.top();
stk.pop();
operand1 = stk.top();
stk.pop();
stk.push(operand1 * operand2);
}
else if (RPN[i] == "/")
{
operand2 = stk.top();
stk.pop();
operand1 = stk.top();
stk.pop();
if (operand2 == 0)
{
return 0;
}
stk.push(operand1 / operand2);
}
else
{
stk.push(atoi(RPN[i].c_str()));
}
}
int ans = stk.top();
stk.pop();
return ans;
}

运算无效

表达式中出现 "除以0" 或求 "tan(π/2)" 表示运算无效,四个选项中必然包含一个 "无效" 选项。

经验、教训总结

  1. 注意版本控制。在开发过程中,实现一个功能并反复测试后,可以整合成一个版本。很多时候觉得在添加功能后,导致整个工程编译不通过而且找不出原因,无奈之下只能重新开始慢慢添加功能并反复测试,这非常浪费时间。

  2. 结对编程尽量面对面交流。开发前期两人讨论完设计框架后就采用线上交流的方式开发,作为后端开发,我提供的接口的功能是正常的,但是参数个数和返回值却不是前端伙伴所需要的,而伙伴在线上也难以清楚具体描述需求,来来回回修改一个又一个版本非常浪费时间。而面对面交流,可以清楚明白伙伴需要什么,迅速开发出相应的接口。

  3. 帮助伙伴开发。伙伴在开发过程中可以在旁观看,作为旁观者经常能即使发现问题并提醒伙伴修正,不至于让伙伴一个人也许为了一个小问题 debug 很长时间,可以极大提高开发效率。

效果展示

  1. 登录注册界面

  2. 做题界面



结对项目总结 -- 基于Qt开发的win10桌面应用的更多相关文章

  1. 基于QT开发的第三方库

    基于Qt开发的第三方库 分类: Qt2014-02-12 11:34 1738人阅读 评论(0) 收藏 举报 QT第三方库   目录(?)[+]   文章来源:http://blog.csdn.net ...

  2. 基于Qt的A*算法可视化分析

    代码地址如下:http://www.demodashi.com/demo/13677.html 需求 之前做过一个无人车需要自主寻找最佳路径,所以研究了相关的寻路算法,最终选择A算法,因为其简单易懂, ...

  3. 基于Qt的开源音乐播放器(CZPlayer)

    CZPlayer CZPlayer是基于Qt开发的一款功能强大的音乐播放器,该播放器的论坛地址请点击here,目前CZPlayer已经是第四个版本了,历史版本也分别在我的github上, github ...

  4. 免费开源数字货币交易所——基于Java开发的比特币交易所 | BTC交易所 | ETH交易所 | 数字货币交易所

    本项目是基于Java开发的比特币交易所 | BTC交易所 | ETH交易所 | 数字货币交易所 | 交易平台 | 撮合交易引擎.本项目基于SpringCloud微服务开发,可用来搭建和二次开发数字货币 ...

  5. 【转贴】-- 基于QT的跨平台应用开发

    原帖地址:http://www.cnblogs.com/R0b1n/p/4106613.html 1 Qt简介 Qt是1991年奇趣科技开发的一个跨平台的C++图形用户界面应用程序框架.它提供给应用程 ...

  6. 基于QT的webkit与ExtJs开发CB/S结构的企业应用管理系统

      一:源起       1.何为CB/S的应用程序       C/S结构的应用程序,是客户端/服务端形式的应用程序,这种应用程序要在客户电脑上安装一个程序,客户使用这个程序与服务端通信,完成一定的 ...

  7. 【Qt编程】基于Qt的词典开发系列--后序

    从去年八月份到现在,总算完成了词典的编写以及相关技术文档的编辑工作.从整个过程来说,文档的编写比程序的实现耗费的时间更多.基于Qt的词典开发系列文章,大致包含了在编写词典软件过程中遇到的技术重点与难点 ...

  8. 【Qt编程】基于Qt的词典开发系列<六>--界面美化设计

    本文讲一讲界面设计,作品要面向用户,界面设计的好坏直接影响到用户的体验.现在的窗口设计基本都是扁平化的,你可以从window XP与window 8的窗口可以明显感觉出来.当然除了窗口本身的效果,窗口 ...

  9. 【Qt编程】基于Qt的词典开发系列<三>--开始菜单的设计

    这篇文章讲讲如何实现开始菜单(或者称为主菜单)的设计.什么是开始菜单呢?我们拿常用的软件来用图例说明,大多数软件的开始菜单在左下角,如下图: 1.window 7的开始菜单 2.有道词典的主菜单 3. ...

  10. 【Qt编程】基于Qt的词典开发系列<一>--词典框架设计及成品展示

    去年暑假的时候,作为学习Qt的实战,我写了一个名为<我爱查词典>的词典软件.后来由于导师项目及上课等原因,时间不足,所以该软件的部分功能欠缺,性能有待改善.这学期重新拿出来看时,又有很多东 ...

随机推荐

  1. TDSQL-C 真·秒级启停:连接断了,又没断

    你听过多少款无服务器架构(Serverless)数据库? 什么是Serverless呢?简单理解,Serverless 分为 FaaS 和 BaaS 两个部分,其中 FaaS 指的是函数即服务,Baa ...

  2. 如何在JavaScript中使用for循环

    前言 循环允许我们通过循环数组或对象中的项并做一些事情,比如说打印它们,修改它们,或执行其他类型的任务或动作.JavaScript有各种各样的循环,for循环允许我们对一个集合(如数组)进行迭代. 在 ...

  3. 简单的sql注入2

    尝试 1 1' 1" 发现1'还是会报错,所以注入口还是1' 再试试1' and '1'='1发现报出SQLi detected! 取消空格试试1'and'1'='1 似乎可以进入,应该就是 ...

  4. SocketException 不知道这样的主机(Quartz.;Dns.GetHostEntry;new HttpChannel)问题记录

    今天发现自己封装的一个Quartz服务无法启动了,跟踪代码才发现了一个问题是因为数字计算机名称导致的,修改了下计算机名称解决了问题.

  5. windows使用pyinstaller 打包sklearn模块出现死循环报错

    前言 解决这个让我花费了很长时间, 我这里说的死循环,不是正常通过 --hidden-import能解决的问题. 因为我也查询了很多资料 但是无一例外都失败了(能通过 –hidden-import 解 ...

  6. nginx配置文件单独创建和管理

    在nginx主配置文件nginx.conf的http模块下引入配置文件夹(注意路径的正确性) 1.nginx主配置文件备份后编辑(nginx配置存放位置:/usr/local/nginx/conf/) ...

  7. 【每日一题】【双端降序队列Deque】2021年12月28日-239. 滑动窗口最大值

    给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 来源:力扣(L ...

  8. 【每日一题】【回溯】【StringBuilder】2021年12月7日-17. 电话号码的字母组合

    给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合.答案可以按 任意顺序 返回. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 来源:力扣(LeetCode)链 ...

  9. [数学建模]主成分分析法PCA

    最常用的线性降维方法,通过某种线性投影,将高维的数据映射到低维的空间中,并期望在所投影的维度上数据的信息量最大(方差最大),以此使用较少的数据维度,同时保留住较多的原数据点的特性. Q1:为何选取方差 ...

  10. ChatGPT杀疯了,这人工智能也太离谱了吧

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/2ac8440d.html 你好,我是测试蔡坨坨. 这几天被ChatGPT刷屏,各大网站平台都能看到关于它的文章和视频,上线短 ...