担任角色

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

开发环境

前端采用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. Python基础部分:8、for循环和range的使用

    目录 一.while循环补充说明 1.死循环 2.嵌套及全局标志位 二.for...循环 1.for...循环特点 2.for...循环语法结构 三.range方法 1.什么是range 2.不同版本 ...

  2. Day1:Markdown文本基础操作

    Markdown学习 标题 一级标题 输入:#+空格+标题名字 :快捷键(Ctrl+1~6) 二级标题 输入:##+空格+标题名字 为二级标题 依次加#(最多六级标题) 三级标题 四级标题 字体 He ...

  3. 我的Vue之旅 10 Gin重写后端、实现页面详情页 Mysql + Golang + Gin

    第三期 · 使用 Vue 3.1 + Axios + Golang + Mysql + Gin 实现页面详情页 使用 Gin 框架重写后端 Gin Web Framework (gin-gonic.c ...

  4. 28分钟学会Linux三剑客

    把简单的技术学到极致就是高手. 前言 Linux三剑客指的是grep.sed以及awk命令的使用,这三个命令功能异常强大,大到没朋友.grep命令主打"查找",sed命令主打&qu ...

  5. IPV4地址详解

    在互联网时代,相信会上网的人应该对IP地址都不是很陌生.就像我们每个人都有一个身份证号码一样,网络里的每个终端都使用一个IP地址用于标示自己.那么你知道哪些是保留地址?哪些是特殊地址吗? 一.保留地址 ...

  6. 聊聊如何让办公网络直连Kubernetes集群PodIP/ClusterIP/Service DNS等

    想象一下,如果您日常使用的研发测试Kubernetes集群,能够有以下效果: 在办公网络下直接访问Pod IP 在办公网络下直接访问Service Cluster IP 在办公网络下直接访问集群内部域 ...

  7. Linux 系统环境监测

    Linux系统环境监测 Linux系统环境主要监测CPU.内存.磁盘I/O和网络流量. 1. CPU (1) 查看CPU的负载情况:uptime 可以通过uptime查看系统整体的负载情况. 如果服务 ...

  8. 【离线数仓】Day01-用户行为数据采集:数仓概念、需求及架构、数据生成及采集、linux命令及其他组件常见知识

    一.数据仓库概念 二.项目需求及架构设计 1.需求分析 2.项目框架 3.框架版本选型 服务器选型:云主机 服务器规划 三.数据生成模块 1.数据基本格式 公共字段:所有手机都包含 业务字段:埋点上报 ...

  9. webShell攻击及防御

    最近公司项目也是经常被同行攻击,经过排查,基本定位都是挂马脚本导致,所以针对webShell攻击做一下记录. 首先简单说下 什么是webShell? 利用文件上传,上传了非法可以执行代码到服务器,然后 ...

  10. java中的自增运算

    本文主要阐明java中的自增运算 1.当i ++ 与 ++ i作为单独语句时,作用与i = i +1一样 2.当赋值时,结果就不一样了 temp = i ++: 操作顺序:1)temp = i: 2) ...