结对项目总结 -- 基于Qt开发的win10桌面应用
担任角色
在这次结对项目中,由于采用了我的个人项目作为参考,所以我继续担任后端开发的角色。
开发环境
前端采用Qt Creator4.13.2 (Community)
后端采用C++
如何复用个人项目
通过对结对项目需求的分析,需要实现的功能大致如下:
注册和登录
修改密码
生成题目
题目作答并统计结果
详细功能需求描述和设计框架见下文 “整体设计框架”。
复用的个人项目的工程框架如下
Headers
User.h
SystemPrompt.h
TreeNode.h
RandomizeTestPaper.h
Sources
main.cpp
User.cpp
SystemPrompt.cpp
TreeNode.cpp
RandomizeTestPaper.cpp
通过了解结对项目的功能需求,经过讨论,决定采用以下复用方式
复用个人项目中随机生成题目的部分,即 TreeNode 和 RandomizeTestPaper 这两部分。小学题目不需要更改,但初中题目中涉及复杂的平方根运算,高中题目的三角函数也都是与 π 无关的弧度角。当这些情况都合在一起的时候,除了利用库函数计算出小数结果(这样对计算机而言都是可行的,但是对用户的使用体验是极不友好的),难以表示表达式的结果,因此需要对这两个难度的题目进行调整,详见下文“表达式求值”部分。初高的题目调整后,在个人项目的基础上增加 “表达式求值” 功能即可。
User 部分与结对项目需求中的 “注册和登录” 有一定的相关度,添加和完善一些功能即可复用。
SystemPrompt 部分主要是用于输出一些系统提示,与结对项目需求基本无关,不考虑复用。
整体设计框架
在清楚如何复用对个人项目的情况下,经过讨论得出结对项目的大致设计框架

表达式求值
添加限制规则的目的:让题目的难度符合正常的小初高试卷难度``
为了避免了平方、开平方、三角函数运算产生的复杂浮点数中间结果对整个表达式求解产生的严重阻碍,我们对小初高运算进行了如下限制:
小学表达式不作任何改变。
初中表达式中,平方内的运算结果一定在[-100, 100]之间,避免计算大数的平方;开平方内的运算结果一定是[1, 400]之间的平方数,保证开平方的结果是整数。
高中表达式中,三角函数全都是与 π 有关的特殊角,计算结果一定是-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)" 表示运算无效,四个选项中必然包含一个 "无效" 选项。
经验、教训总结
注意版本控制。在开发过程中,实现一个功能并反复测试后,可以整合成一个版本。很多时候觉得在添加功能后,导致整个工程编译不通过而且找不出原因,无奈之下只能重新开始慢慢添加功能并反复测试,这非常浪费时间。
结对编程尽量面对面交流。开发前期两人讨论完设计框架后就采用线上交流的方式开发,作为后端开发,我提供的接口的功能是正常的,但是参数个数和返回值却不是前端伙伴所需要的,而伙伴在线上也难以清楚具体描述需求,来来回回修改一个又一个版本非常浪费时间。而面对面交流,可以清楚明白伙伴需要什么,迅速开发出相应的接口。
帮助伙伴开发。伙伴在开发过程中可以在旁观看,作为旁观者经常能即使发现问题并提醒伙伴修正,不至于让伙伴一个人也许为了一个小问题 debug 很长时间,可以极大提高开发效率。
效果展示
登录注册界面

做题界面


结对项目总结 -- 基于Qt开发的win10桌面应用的更多相关文章
- 基于QT开发的第三方库
基于Qt开发的第三方库 分类: Qt2014-02-12 11:34 1738人阅读 评论(0) 收藏 举报 QT第三方库 目录(?)[+] 文章来源:http://blog.csdn.net ...
- 基于Qt的A*算法可视化分析
代码地址如下:http://www.demodashi.com/demo/13677.html 需求 之前做过一个无人车需要自主寻找最佳路径,所以研究了相关的寻路算法,最终选择A算法,因为其简单易懂, ...
- 基于Qt的开源音乐播放器(CZPlayer)
CZPlayer CZPlayer是基于Qt开发的一款功能强大的音乐播放器,该播放器的论坛地址请点击here,目前CZPlayer已经是第四个版本了,历史版本也分别在我的github上, github ...
- 免费开源数字货币交易所——基于Java开发的比特币交易所 | BTC交易所 | ETH交易所 | 数字货币交易所
本项目是基于Java开发的比特币交易所 | BTC交易所 | ETH交易所 | 数字货币交易所 | 交易平台 | 撮合交易引擎.本项目基于SpringCloud微服务开发,可用来搭建和二次开发数字货币 ...
- 【转贴】-- 基于QT的跨平台应用开发
原帖地址:http://www.cnblogs.com/R0b1n/p/4106613.html 1 Qt简介 Qt是1991年奇趣科技开发的一个跨平台的C++图形用户界面应用程序框架.它提供给应用程 ...
- 基于QT的webkit与ExtJs开发CB/S结构的企业应用管理系统
一:源起 1.何为CB/S的应用程序 C/S结构的应用程序,是客户端/服务端形式的应用程序,这种应用程序要在客户电脑上安装一个程序,客户使用这个程序与服务端通信,完成一定的 ...
- 【Qt编程】基于Qt的词典开发系列--后序
从去年八月份到现在,总算完成了词典的编写以及相关技术文档的编辑工作.从整个过程来说,文档的编写比程序的实现耗费的时间更多.基于Qt的词典开发系列文章,大致包含了在编写词典软件过程中遇到的技术重点与难点 ...
- 【Qt编程】基于Qt的词典开发系列<六>--界面美化设计
本文讲一讲界面设计,作品要面向用户,界面设计的好坏直接影响到用户的体验.现在的窗口设计基本都是扁平化的,你可以从window XP与window 8的窗口可以明显感觉出来.当然除了窗口本身的效果,窗口 ...
- 【Qt编程】基于Qt的词典开发系列<三>--开始菜单的设计
这篇文章讲讲如何实现开始菜单(或者称为主菜单)的设计.什么是开始菜单呢?我们拿常用的软件来用图例说明,大多数软件的开始菜单在左下角,如下图: 1.window 7的开始菜单 2.有道词典的主菜单 3. ...
- 【Qt编程】基于Qt的词典开发系列<一>--词典框架设计及成品展示
去年暑假的时候,作为学习Qt的实战,我写了一个名为<我爱查词典>的词典软件.后来由于导师项目及上课等原因,时间不足,所以该软件的部分功能欠缺,性能有待改善.这学期重新拿出来看时,又有很多东 ...
随机推荐
- 开源网络协议栈onps诞生记
小孩没娘,说来话长,一切都要从LwIP说起.大约是06年9月,本人在二姨的坛口发布了一篇小文--<uC/OS-II 平台下的 LwIP 移植笔记>.自此一发不可收拾,开启了一段我与LwIP ...
- Docker遇见golang https://www.jianshu.com/p/37693eb8f646
golang logo 在我国古代,传说天庭中有种种天兵天将,有看守四大天门的(docker0网桥),有负责传话的门将(REST API),有负责人间和天界联络的,如财神爷,土地公等(NAT,DNS) ...
- Centos7.6分区、格式化、自动挂载磁盘
个人名片: 对人间的热爱与歌颂,可抵岁月冗长 Github:念舒_C.ying CSDN主页️:念舒_C.ying 个人博客 :念舒_C.ying 目录 1. 添加硬盘 2. 执行fdisk -l ...
- 搜索与图论篇——DFS和BFS
搜索与图论篇--DFS和BFS 本次我们介绍搜索与图论篇中DFS和BFS,我们会从下面几个角度来介绍: DFS和BFS简介 DFS数字排序 DFS皇后排序 DFS树的重心 BFS走迷宫 BFS八数码 ...
- Bugku md5 collision
题目名字都叫md5碰撞,那就肯定和md5碰撞脱不了关系了 打开题目,首先让我们输入a 行吧,随意post一个a=1进去 结果提示flase 这里应该是有特殊值,我们找找看 查看源码,抓包 没找到 试试 ...
- (GCC) gcc 编译选项 -fno-omit-frame-pointer,-fno-tree-vectorize,fno-optimize-sibling-calls;及内存泄漏、非法访问检测 ASAN
omit-frame-pointer 开启该选项,主要是用于去掉所有函数SFP(Stack Frame Pointer)的,即在函数调用时不保存栈帧指针SFP,代价是不能通过backtrace进行调试 ...
- ArcEngine要素编辑遇到的一些问题
1.如何开启编辑 IMap myMap = this._Aplication.ActiveView.FocusMap; IWorkspace myWorkspace = (myMap25Sheet.P ...
- HCIE Routing&Switching之MPLS LDP理论
前文我们了解了MPLS的静态LSP配置相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16937104.html:今天我们来聊一聊标签分发协议LDP相关 ...
- Flink SQL管理平台flink-streaming-platform-web安装搭建
文章都在个人博客网站:https://www.ikeguang.com/ 同步,欢迎访问. 最近看到有人在用flink sql的页面管理平台,大致看了下,尝试安装使用,比原生的flink sql界面确 ...
- C++日期和时间编程总结
一,概述 二,C-style 日期和时间库 2.1,数据类型 2.2,函数 2.3,数据类型与函数关系梳理 2.4,时间类型 2.4.1,UTC 时间 2.4.2,本地时间 2.4.3,纪元时间 2. ...