[2019BUAA软件工程]结对做业

 

Tips Link
做业连接 [2019BUAA软件工程]结对做业
GitHub地址 WordChain

PSP表格

psp2.1   预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 40
. Estimate · 估计这个任务须要多少时间 900 1200
Development 开发 700 900
. Analysis · 需求分析 (包括学习新技术) 60 60
. Design Spec · 生成设计文档 100 120
.Design Review · 设计复审 (和同事审核设计文档) 40 20
.Coding Standard · 代码规范 (为目前的开发制定合适的规范 40 30
.Design · 具体设计 60 50
.Coding · 具体编码 200 320
.Code Review · 代码复审 100 200
.Test · 测试(自我测试,修改代码,提交修改) 100 100
Reporting 报告 200 300
.Test Report · 测试报告 60 100
.Size Measurement · 计算工做量 100 120
.Postmortem & Process Improvement Plan · 过后总结, 并提出过程改进计划 40 80
  合计 960 1240

 

模块化设计思想

一、信息隐藏(Information Hiding)

In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change). git

以上部分摘自维基百科中对information hidding定义。信息隐藏的主要实现方式即便对咱们本身程序的封装,好比将功能稳定的函数,抽象出来封装为私有,以实如今作出修改时,尽量的保证程序其他部分的正确性,减小维护难度。另外一方面,将程序中的变量都封装位私有,将这些信息隐藏起来,也能够较好的保证用户信息安全。github

在咱们的程序中,咱们采用将不少功能抽象出子函数,只给用户暴漏了一个计算的入口函数,较好的实现了信息封装以及程序的可维护性,全部的变量也都采用私有变量的形式,加强了信息安全的可靠性。算法

 

二、接口设计(Interface Design)

User interface design (UI) or user interface engineering is the design of user interfaces for machines and software, such as computers, home appliances, mobile devices, and other electronic devices, with the focus on maximizing usability and the user experience.编程

以上部分摘自维基百科中对interface design 定义。接口设计的主要目的,是为了其余的用户或者应用提供一个应用或者用户能够直接使用的功能接口(即便别人彻底不知道内部实现也能够轻易使用),原则就是封装的越彻底越好,接口调用越简单越好。在咱们的程序中,采用和做业指导中相同的接口设计,一方面实现了对程序功能较好的封装,一方面也极大的方便了咱们与其余同窗的耦合。后端

三、下降耦合(Loose Coupling)

In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components. Subareas include the coupling of classes, interfaces, data, and services.[1] Loose coupling is the opposite of tight coupling.数组

以上部分摘自维基百科中对loose coupling定义. 程序中模块之间的耦合性主要是体如今模块之间的依赖关系,下降模块之间的耦合性,既能够最大程度上的实现模块中的功能分离,也能够更方便的对模块的功能之间进行测试。在咱们的程序中方,咱们将数据出来模块,与运算 模块彻底独立 开,经过接口传递数据,极大的下降了模块之间的依关系,也较好的方便了对每一个模块正确性的单独测试。安全

计算模块接口的设计与实现过程

对外接口设计:

  • 接口:app

bool gen_chain_word(vector<string> &words, vector<string> &output, char head, char tail, bool enable_loop);
bool gen_chain_char(vector<string> &words, vector<string> &output, char head, char tail, bool enable_loop);
  • 参数解释:electron

    • vector<string> &words:传入单词集合。模块化

    • vector<string> &output:输出单词链。

    • char head:单词链首字母限制。无限制输入0,有限制则输入相应英文字符。

    • char tail:单词链首字母限制。无限制输入0,有限制则输入相应英文字符。

    • bool enable_loop:单词环限制。容许存在单词换为true,不然为false

类功能设计:

  1. Core:内外层交互类

    • 实现计算模块与外层(Console或GUI模块)交互逻辑。

    • 接收外层的原始数据和相应参数。

    • 对接收到的原始数据进行预处理:

      • 从原始数据中提取出单词。

      • 过滤重复单词。

      • 将有效单词按首尾字母归类,存入单词库中。

      • 更新单词库中单词连接矩阵。

    • 按照指定模式组织内层计算逻辑。

    • 返回内层计算结果。

  2. Solve/DPSolve:核心计算类

    • 实现对已有单词库搜索单词链的算法。

    • 核心算法:优化BFS(有单词环)和动态规划(无单词环)。

    • 辅助算法:拓扑排序(检查是否存在单词环)。

  3. WordList:数据类

    • 格式化存储单词。

    • 将单词连接关系组织为邻接矩阵。

    • 提供相应的查询函数。

类流程关系

  1. Core获取原始数据与运行参数。

  2. Core预处理原始数据,生成单词库(WordList)。

  3. 按照参数启动Solve/DPSolve相应计算函数。

  4. 完成单词链搜索,Core输出计算结果。

 

类关键函数设计及实现

  1. Core:

    • 关键函数:

      • gen_chain_word():按单词数量搜索单词链时的对外接口。

      • gen_chain_char():按单词长度搜索单词链时的对外接口。

  2. WordList:

    • 存储结构设计思路:

      1. 单词表组织: 将消除重复后的单词按照首尾字母进行归类。好比:apple归类为ae类单词。为每一种类的单词创建数组存储,每一个数组内的同种单词按照长度降序排列。对存储每一种类单词的数组按照HASH表存储至一维数组中。

      2. 辅助结构组织: 根据已经创建的单词表,将字母视为节点,单词视为由首字母结点指向尾字母的有向边,则可以将单词表组织为有向图。使用位图存储邻接矩阵,使用HASH数组存储各结点的入度。

      3. HASH函数:Index = 首字母相对'a'偏移 * 26 + 尾字母相对'a'偏移

    • 成员变量:

      • m_list:单词表,按照首尾字母的种类对单词进行分组储存,存储采用HASH结构,不存在重复单词,同种类单词按照长度由长至短排列。

      • m_iListSize:单词表长度,存储不一样首尾字母的单词数量。

      • m_iListGetPoint:单词检索索引,存储已检索的单词的索引。

      • m_iArryMatrix[]:单词链邻接矩阵。

      • m_iArrayNodeIn[]:结点入度数组。

    • 关键函数:

      • parseString()

        • 解析字符串,提取单词。

        • 调用私有函数addWord添加单词。

      • getWordAt()

        • 获取符合首尾条件的单词。

        • 可以支持对相同单词的不重复搜索与重复搜索。

      • getWordSumAt()

        • 获取符合首尾条件的单词总数量

      • getWordRemainingAt()

        • 获取符合首尾条件的单词剩余数量

        • 剩余数量指未被操做搜索过的单词。

      • undoGetWordAt()

        • 撤销单词不重复搜索操做,即撤销对某首尾单词的前一次不重复搜索操做。

      • getNodeIn()

        • 获取单词链图某一首字母结点的入度。

      • getNodeNext()

        • 获取单词链图某一首字母结点的邻接矩阵项。

      • addWord()"private"

        • 过滤重复单词,将有效单词添加至单词表相应分类。

        • 保证添加后各分类内单词长度降序排列。

  3. Solve:

    • 实验思路

      • 使用深度优先搜索加剪枝策略,解决了头尾限定问题,以及属于单词序列中存在环时得问题。

      • 成员变量:

        • word

        • m_iSigned26 标记两个字母之间的路径是否以及走过

        • m_ihead[26] 标记每一个字母是否以及用过

        • m_ans676 记录单词是否使用的变量

        • next_tag26 储存字母邻接链表

        • max_dfs[26] 记录每一个单词距离终点的最大距离

        • final_dfs[26] 记录最终的每一个字母节点距离其重点的距离

        • m_FinalLen 单词链最终长度

        • m_TemLen 搜索到的当前字符链的长度

        • max_num 单词链个数最大长度

        • temp_num 搜索到的单词链表当前个数

        • bool is_circle 判断是否有环

        • head 肯定头部字母记录下的头部字母

        • char m_Mode 记录搜索模式的变量

        • char m_ModeHead 记录搜索的时指定的头部

        • char m_ModeTail 记录搜索的时指定的尾部

        • bool m_ModeRing 记录搜索模式是否有环

        • vector <string> m_FinalChain; 最终结果

        • vector <string> m_TempChain; 当前路径

      • 关键方法

      • Solve1() 解决容许有环时的搜索问题

      • Solve2_he() 解决无环时的指定头尾的搜索问题

      • Dfs_solve1() 解决容许有环时的搜索问题的搜索函数

      • cmp() 容许有环的时候对当前最大长度的更新函数

      • printChain() 容许有环的时候的输出函数

      • Dfs_solvehe() 指定头尾问题的搜索问题的递归搜索函数

      • cmp_he() 解决头尾指定问题时候 对当前最大长度进行更新的函数

      • printhe() 解决头尾指定问题时候 的输出问题

         

  4. DPSolve:

    • 实现思路:

      • 使用动态规划解决无单词环状况下除同时限定单词链首尾的问题。根据限制条件的不一样采起正向或逆向动态规划。

      • 动态规划:

        • 正向递推式:F(c1)=max{F(c1)+len(c1ci)}F(c1)=max{F(c1)+len(c1ci)}

        • 逆向递推式:f(c1)=max{f(c1)+len(cic1)}f(c1)=max{f(c1)+len(cic1)}

        • F(c)为由c开始的最长单词链长度。

        • f(c)为以c结束的最长单词链长度。

        • len(cicj)是以ci为首以cj为尾的最长单词长度。

      • 单词环检测:

        • 使用拓扑排序算法检测单词环,保证动态规划正确进行。

    • 成员变量:

      • m_ptrWordList:单词表指针。

      • m_cMode:搜索模式,分为按数量和按程度。

      • m_cModeHead:头部限定。

      • m_cModeTail:尾部限定。

      • m_iArrayDp[]:动态规划结果。

      • m_iArrayNext[]:存储相应结点的最优后继结点。

      • m_iArrayBefore[]:存储相应结点的最优前缀结点。

      • m_iQueueTopo:拓扑排序结果。

      • m_strVecWordChain:存储计算获得的单词链。

    • 关键方法:

      • DPSolve():构造函数,传入单词表和各类参数。

      • startDPSolve():启动函数。

      • topoSort():拓扑排序,检查单词表中是否有环。

      • getWordChain():导出计算后的结果。

      • DPStep(int indexH):正向动态规划子函数,私有函数。

      • DPStepRe(int indexH):逆向动态规划子函数,私有函数。

 

UML设计

 

 

 

 

 

计算模块接口部分的性能改进

  • 第一阶段:深度搜索实现基本功能

笔者在最初进行程序设计时采起的是使用简洁的方法先实现需求的全部功能,再根据实际运行状况优化算法。根据这样的初衷产生了以下的流程设计。 首先,将全部单词按照首尾字母进行分类。以字母为结点,以单词为有向边(由单词首字母结点指向尾字母节点),将单词表构形成图结构。如此组织单词表能够很好地对需求中的问题进行简化和抽象:无单词环时,很容易证实每一个结点间最多单向通过一次。好比'a'、'b'两结点最多仅能有一个有向边。因而即可以将问题转化为在构造的图中搜索最长路径。对于‘-w’功能则是将边权重设置为‘1’;对于‘-c’功能则是将边权重设置为该边对应类型单词中最长的单词长度;而‘-t’和‘-h’功能则是增长了首尾节点的限制。而对于有单词环的状况,每一个结点间可通过的方向及其次数等于其所对应种类的单词数量,运用深度搜索也一样可以解决相应的问题。 在搜索阶段,程序对每一个节点进行深度搜索,搜索以该结点为首的最长路径,并根据不一样的输入参数得出符合要求的单词链。最终经过接口完成结果的输出。

  • 第二阶段:动态规划优化部分功能

笔者的小组在较短期内就完成了基于深度搜索的单词链搜索程序。在经过正确性测试并进行性能测试后,不出意料的出现的运行效率低的问题。运行效率低的主要缘由是原始深度遍历不具备记忆和预测功能。这会致使在进行屡次遍历时会对以搜索的路径和明显不是最优解的路径进行遍历。会通过分析后,咱们决定采起如下方案对程序进行优化。 对于无单词环而且不一样时限定首尾的状况,废弃原先的方法转而采用动态规划的方法。这几个搜索最长单词链的问题能够分解为求解与其相连的字母的最长单词链加上二者间距离的最大值。好比正向动态规划时,求解以'a'为首的最长单词链,而'b'、'c'结点能够由'a'结点直接到达,则原问题的最优解为子问题'b'、'c'的最优解分别加上'a'到这些结点的边的权值。用公式表示为: 正向递推式:F(c1)=max{F(c1)+len(c1ci)}*或*F(c1)=max{F(c1)+len(c1ci)} 逆向递推式:f(c1)=max{f(c1)+len(cic1)}*或*f(c1)=max{f(c1)+len(cic1)} 在使用动态规划后,程序将无单词环而且不一样时限定首尾的状况的计算压缩至了1s内,基本知足了要求。

  • 第三阶段:优化深度搜索

    在进行动态规划的优化以后,咱们发现,动态规划虽然效率很高,可是并不能处理同时指定头和尾的问题,因而咱们仿照动态规划表达式的思想,对于咱们的深度优先搜索作了一步剪枝。具体的剪枝思想以下:

    在搜索回退的时候,用一个数组,记录下每一个字母距离其末尾的最大长度,或者最大单词个数,当第二次搜索到这个字母节点时,直接比较当前长度,当前节点距离末尾的最大长度,若是前者比后者小,直接剪掉这个分支。保证了每条边只搜索了一遍,极大的提升了深度优先搜索的效率。

  • 性能测试:

 

上图为在无单词环的状况下进行的约九千单词量的性能测试结果。由图可知,在进行vector操做上的消耗较多。消耗最多的代码是在addWord函数中将新单词加入至有序单词表的操做时采用了vector的insert函数。这一消耗仅出如今预处理的部分,在保证单词表中的单词是按照长度降序排列的同时还过滤了重复的单词。该操做虽然带来了必定的损耗,可是组织好的单词表更易于计算过程的检索,下降了检索的复杂度,防止递归致使的消耗的放大。计算过程采用的动态规划算法大大减少了该阶段的消耗。

 

上图为在有单词环的状况下进行的性能测试。CPU的消耗主要出在递归调用的函数Dfs_solve1中。

契约式编程的优缺点

Design by contract (DbC), also known as contract programming, programming by contract and design-by-contract programming, is an approach for designing software. It prescribes that software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants.

以上是维基百科对契约式编程的释义。有维基百科释义可知,契约式编程中,每一个模块有明确的契约关系,模块互相调用的时候都有责任有义务向调用本身的模块保证使用的正确性以及本身功能的正确性。

契约编程的优缺点以下

优势:

一、程序的总体设计更为优秀

为了符合契约式编程的核心思想,编程者必须在编程以前就要有个更好的总体设计以便于能更好的完成本身的契约,保证程序的正确性。为了有更易于使用的接口,更正确的内部功能,必须有更清楚的设计,更简单的设计。

二、提升系统可靠性,鲁棒性

只要各个模块都遵照契约,那么必定程度上就大大的下降了模块间耦合时之间的Bug。程序的鲁棒性也获得了很好的提高。

三、出色的文档

契约乃是类特性的公用视图中的固有成分,契约是值得信赖的文档(运行时要检查断言,以保证制定的契约与程序的实际运行状况一致)。

缺点:

一、提升了编程的撰写成本

为了符合规范,并符合契约精神,编写的时候必需要更加注意这些细节上的内容,增长了代码编写的成本。

二、须要有不少编程经验

为了真正的实现契约式编程,对编码者的实际编程经验也有较高的要求,须要编程着有较好的编程基础以及必定的编程意识才能真正的完成契约式编程。

契约式编程的应用

在撰写类的时候,每一个类都单独进行测试,封装前确保了调用时的便宜性和功能的正确性。在封装运算程序与GUI的时候也作到了 契约式编程,极大的方便了对接与测试。

计算模块部分单元测试展现

笔者对工程中Core类的正确性以及封装后的dll的正确性进行了测试

  • Core类测试集

  1 TEST_CLASS(TEST)
  2 {
  3 public:
  4   5 Core *CORE = NULL;
  6   7 TEST_METHOD_INITIALIZE(initEnv)
  8 {
  9     CORE = new Core();
 10 }
 11  12 TEST_METHOD_CLEANUP(cleanWordList)
 13 {
 14     delete CORE;
 15     CORE = NULL;
 16 }
 17  18 TEST_METHOD(Test_1)             // -w
 19 {
 20     string words[] = {
 21         "ab",
 22         "accccccccccccccccccccc",
 23         "ad",
 24         "bc",
 25         "bd",
 26         "cd",
 27     };
 28     string ans[] = {
 29         "ab", "bc", "cd"
 30     };
 31     vector<string> *lines = new vector<string>();
 32     vector<string> *chain = new vector<string>();
 33     for(int i = 0; i < 6; i++)
 34     {
 35         lines->push_back(words[i]);
 36     }
 37     Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 0, false));
 38     Assert::AreEqual(size_t(3), chain->size());
 39     Assert::AreEqual(ans[0], (*chain)[0]);
 40     Assert::AreEqual(ans[1], (*chain)[1]);
 41     Assert::AreEqual(ans[2], (*chain)[2]);
 42     delete lines;
 43     delete chain;
 44 }
 45  46 TEST_METHOD(Test_2)             // -c
 47 {
 48     string words[] = {
 49         "ab",
 50         "accccccccccccccccccccc",
 51         "ad",
 52         "bc",
 53         "bd",
 54         "cd",
 55     };
 56     string ans[] = {
 57         "accccccccccccccccccccc", "cd"
 58     };
 59     vector<string> *lines = new vector<string>();
 60     vector<string> *chain = new vector<string>();
 61     for (int i = 0; i < 6; i++)
 62     {
 63         lines->push_back(words[i]);
 64     }
 65     Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 0, false));
 66     Assert::AreEqual(size_t(2), chain->size());
 67     Assert::AreEqual(ans[0], (*chain)[0]);
 68     Assert::AreEqual(ans[1], (*chain)[1]);
 69     delete lines;
 70     delete chain;
 71 }
 72  73 TEST_METHOD(Test_3)             // -w -h
 74 {
 75     string words[] = {
 76         "ab",
 77         "accccccccccccccccccccc",
 78         "ad",
 79         "bc",
 80         "bdddd",
 81         "cd",
 82     };
 83     string ans[] = {
 84         "bc", "cd"
 85     };
 86     vector<string> *lines = new vector<string>();
 87     vector<string> *chain = new vector<string>();
 88     for (int i = 0; i < 6; i++)
 89     {
 90         lines->push_back(words[i]);
 91     }
 92     Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 'b', 0, false));
 93     Assert::AreEqual(size_t(2), chain->size());
 94     Assert::AreEqual(ans[0], (*chain)[0]);
 95     Assert::AreEqual(ans[1], (*chain)[1]);
 96     delete lines;
 97     delete chain;
 98 }
 99 100 TEST_METHOD(Test_4)// -c -h
101 {
102 string words[] = {
103 "ab",
104 "accccccccccccccccccccc",
105 "ad",
106 "bc",
107 "bdddd",
108 "cd",
109 "dd",
110     };
111 string ans[] = {
112 "bdddd", "dd"
113     };
114 vector<string> *lines = new vector<string>();
115 vector<string> *chain = new vector<string>();
116 for (int i = 0; i < 7; i++)
117     {
118 lines->push_back(words[i]);
119     }
120 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 'b', 0, false));
121 Assert::AreEqual(size_t(2), chain->size());
122 Assert::AreEqual(ans[0], (*chain)[0]);
123 Assert::AreEqual(ans[1], (*chain)[1]);
124 delete lines;
125 delete chain;
126 }
127 128 TEST_METHOD(Test_5)// -w -t
129 {
130 string words[] = {
131 "ab",
132 "accccccccccccccccccccc",
133 "ad",
134 "bc",
135 "bdddd",
136 "cd",
137     };
138 string ans[] = {
139 "ab", "bc"
140     };
141 vector<string> *lines = new vector<string>();
142 vector<string> *chain = new vector<string>();
143 for (int i = 0; i < 6; i++)
144     {
145 lines->push_back(words[i]);
146     }
147 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 'c', false));
148 Assert::AreEqual(size_t(2), chain->size());
149 Assert::AreEqual(ans[0], (*chain)[0]);
150 Assert::AreEqual(ans[1], (*chain)[1]);
151 delete lines;
152 delete chain;
153 }
154 155 TEST_METHOD(Test_6)// -c -t
156 {
157 string words[] = {
158 "ab",
159 "accccccccccccccccccccc",
160 "ad",
161 "bc",
162 "bdddd",
163 "cd",
164 "cc"
165     };
166 string ans[] = {
167 "accccccccccccccccccccc", "cc"
168     };
169 vector<string> *lines = new vector<string>();
170 vector<string> *chain = new vector<string>();
171 for (int i = 0; i < 7; i++)
172     {
173 lines->push_back(words[i]);
174     }
175 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 'c', false));
176 Assert::AreEqual(size_t(2), chain->size());
177 Assert::AreEqual(ans[0], (*chain)[0]);
178 Assert::AreEqual(ans[1], (*chain)[1]);
179 delete lines;
180 delete chain;
181 }
182 183 TEST_METHOD(Test_7)// -w -h -t
184 {
185 string words[] = {
186 "ab",
187 "accccccccccccccccccccc",
188 "ad",
189 "ae",
190 "bc",
191 "bdddd",
192 "be",
193 "cd",
194 "ce",
195 "de"
196     };
197 string ans[] = {
198 "bc", "cd"
199     };
200 vector<string> *lines = new vector<string>();
201 vector<string> *chain = new vector<string>();
202 for (int i = 0; i < 10; i++)
203     {
204 lines->push_back(words[i]);
205     }
206 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 'b', 'd', false));
207 Assert::AreEqual(size_t(2), chain->size());
208 Assert::AreEqual(ans[0], (*chain)[0]);
209 Assert::AreEqual(ans[1], (*chain)[1]);
210 delete lines;
211 delete chain;
212 }
213 214 TEST_METHOD(Test_8)// -c -h -t
215 {
216 string words[] = {
217 "ab",
218 "accccccccccccccccccccc",
219 "ad",
220 "ae",
221 "bc",
222 "bdddd",
223 "be",
224 "cd",
225 "ce",
226 "de",
227 "dd",
228     };
229 string ans[] = {
230 "bdddd", "dd"
231     };
232 vector<string> *lines = new vector<string>();
233 vector<string> *chain = new vector<string>();
234 for (int i = 0; i < 11; i++)
235     {
236 lines->push_back(words[i]);
237     }
238 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 'b', 'd', false));
239 Assert::AreEqual(size_t(2), chain->size());
240 Assert::AreEqual(ans[0], (*chain)[0]);
241 Assert::AreEqual(ans[1], (*chain)[1]);
242 delete lines;
243 delete chain;
244 }
245 246 TEST_METHOD(Test_9)// -w  but have ring
247 {
248 string words[] = {
249 "ab",
250 "accccccccccccccccccccc",
251 "ad",
252 "ae",
253 "bc",
254 "bdddd",
255 "db",
256 "be",
257 "cd",
258 "ce",
259 "de"
260     };
261 vector<string> *lines = new vector<string>();
262 vector<string> *chain = new vector<string>();
263 for (int i = 0; i < 11; i++)
264     {
265 lines->push_back(words[i]);
266     }
267 Assert::AreEqual(-2, CORE->gen_chain_word(*lines, *chain, 0, 0, false));
268 delete lines;
269 delete chain;
270 }
271 272 TEST_METHOD(Test_10)// -c but have ring
273 {
274 string words[] = {
275 "ab",
276 "accccccccccccccccccccc",
277 "ad",
278 "ae",
279 "bc",
280 "bdddd",
281 "db",
282 "be",
283 "cd",
284 "ce",
285 "de"
286     };
287 vector<string> *lines = new vector<string>();
288 vector<string> *chain = new vector<string>();
289 for (int i = 0; i < 11; i++)
290     {
291 lines->push_back(words[i]);
292     }
293 Assert::AreEqual(-2, CORE->gen_chain_char(*lines, *chain, 0, 0, false));
294 delete lines;
295 delete chain;
296 }
297 298 TEST_METHOD(Test_11)// -w have self
299 {
300 string words[] = {
301 "ab",
302 "accccccccccccccccccccc",
303 "ad",
304 "ae",
305 "bb",
306 "bc",
307 "bdddd",
308 "be",
309 "cc",
310 "cd",
311 "ce",
312 "dd",
313 "de"
314     };
315 string ans[] = {
316 "ab", "bb", "bc", "cc", "cd", "dd", "de"
317     };
318 vector<string> *lines = new vector<string>();
319 vector<string> *chain = new vector<string>();
320 for (int i = 0; i < 13; i++)
321     {
322 lines->push_back(words[i]);
323     }
324 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 0, false));
325 Assert::AreEqual(size_t(7), chain->size());
326 Assert::AreEqual(ans[0], (*chain)[0]);
327 Assert::AreEqual(ans[1], (*chain)[1]);
328 Assert::AreEqual(ans[2], (*chain)[2]);
329 Assert::AreEqual(ans[3], (*chain)[3]);
330 Assert::AreEqual(ans[4], (*chain)[4]);
331 Assert::AreEqual(ans[5], (*chain)[5]);
332 Assert::AreEqual(ans[6], (*chain)[6]);
333 delete lines;
334 delete chain;
335 }
336 337 TEST_METHOD(Test_12){// -c have self
338 string words[] = {
339 "ab",
340 "accccccccccccccccccccc",
341 "ad",
342 "ae",
343 "bb",
344 "bc",
345 "bdddd",
346 "be",
347 "cc",
348 "cd",
349 "ce",
350 "dd",
351 "de"
352     };
353 string ans[] = {
354 "accccccccccccccccccccc", "cc", "cd", "dd", "de"
355     };
356 vector<string> *lines = new vector<string>();
357 vector<string> *chain = new vector<string>();
358 for (int i = 0; i < 13; i++)
359     {
360 lines->push_back(words[i]);
361     }
362 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 0, false));
363 Assert::AreEqual(size_t(5), chain->size());
364 Assert::AreEqual(ans[0], (*chain)[0]);
365 Assert::AreEqual(ans[1], (*chain)[1]);
366 Assert::AreEqual(ans[2], (*chain)[2]);
367 Assert::AreEqual(ans[3], (*chain)[3]);
368 Assert::AreEqual(ans[4], (*chain)[4]);
369 delete lines;
370 delete chain;
371 }
372 373 TEST_METHOD(Test_13)// -w -r
374 {
375 string words[] = {
376 "ab", "aaaaabbbbbccccc", "aaaaaddddd",
377 "bc",
378 "cb", "cd",
379     };
380 string ans[] = {
381 "aaaaabbbbbccccc", "cb", "bc", "cd"
382     };
383 vector<string> *lines = new vector<string>();
384 vector<string> *chain = new vector<string>();
385 for (int i = 0; i < 6; i++)
386     {
387 lines->push_back(words[i]);
388     }
389 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 0, 0, true));
390 Assert::AreEqual(size_t(4), chain->size());
391 Assert::AreEqual(ans[0], (*chain)[0]);
392 Assert::AreEqual(ans[1], (*chain)[1]);
393 Assert::AreEqual(ans[2], (*chain)[2]);
394 Assert::AreEqual(ans[3], (*chain)[3]);
395 delete lines;
396 delete chain;
397 }
398 399 TEST_METHOD(Test_14) {// -c -r
400 string words[] = {
401 "ab", "aaaccc", "aaaaabbbbbcccccddddd",
402 "bc",
403 "cb", "cd",
404 "dd",
405     };
406 string ans[] = {
407 "aaaaabbbbbcccccddddd", "dd"
408     };
409 vector<string> *lines = new vector<string>();
410 vector<string> *chain = new vector<string>();
411 for (int i = 0; i < 7; i++)
412     {
413 lines->push_back(words[i]);
414     }
415 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 0, 0, true));
416 Assert::AreEqual(size_t(2), chain->size());
417 Assert::AreEqual(ans[0], (*chain)[0]);
418 Assert::AreEqual(ans[1], (*chain)[1]);
419 delete lines;
420 delete chain;
421 }
422 423 TEST_METHOD(Test_15) {// -w -r -h -t
424 string words[] = {
425 "ab",
426 "bccccccccccccccccccccccccccc", "bd",
427 "cd",
428 "da", "dc",
429     };
430 string ans[] = {
431 "bd", "dc", "cd", "da"
432     };
433 vector<string> *lines = new vector<string>();
434 vector<string> *chain = new vector<string>();
435 for (int i = 0; i < 6; i++)
436     {
437 lines->push_back(words[i]);
438     }
439 Assert::AreEqual(0, CORE->gen_chain_word(*lines, *chain, 'b', 'a', true));
440 Assert::AreEqual(size_t(4), chain->size());
441 Assert::AreEqual(ans[0], (*chain)[0]);
442 Assert::AreEqual(ans[1], (*chain)[1]);
443 Assert::AreEqual(ans[2], (*chain)[2]);
444 Assert::AreEqual(ans[3], (*chain)[3]);
445 delete lines;
446 delete chain;
447 }
448 449 TEST_METHOD(Test_16) {// -c -r -h
450 string words[] = {
451 "ab",
452 "bccccccccccccccccccccccccccc", "bd",
453 "cd",
454 "da", "dc",
455     };
456 string ans[] = {
457 "bccccccccccccccccccccccccccc","cd", "da"
458     };
459 vector<string> *lines = new vector<string>();
460 vector<string> *chain = new vector<string>();
461 for (int i = 0; i < 6; i++)
462     {
463 lines->push_back(words[i]);
464     }
465 Assert::AreEqual(0, CORE->gen_chain_char(*lines, *chain, 'b', 'a', true));
466 Assert::AreEqual(size_t(3), chain->size());
467 Assert::AreEqual(ans[0], (*chain)[0]);
468 Assert::AreEqual(ans[1], (*chain)[1]);
469 Assert::AreEqual(ans[2], (*chain)[2]);
470 delete lines;
471 delete chain;
472 }
  • 拓扑排序测试

 1 TEST_METHOD(TEST_TopoSort_1)
 2 {
 3     string str_list[] = {
 4         "aa", "abc" , "cbd", "ddd", "da"
 5     };
 6     for (int i = 0; i < 5; i++)
 7     {
 8         WORDLIST->parseString(str_list[i]);
 9     }
10     dpSolve = new DPSolve(WORDLIST, 'w');
11     Assert::AreEqual(false, dpSolve->topoSort());
12 }
13 14 TEST_METHOD(TEST_TopoSort_2)
15 {
16     string str_list[] = {
17         "aa", "abc" , "cbd", "ddd", "db"
18     };
19     for (int i = 0; i < 5; i++)
20     {
21         WORDLIST->parseString(str_list[i]);
22     }
23     dpSolve = new DPSolve(WORDLIST, 'w');
24     Assert::AreEqual(true, dpSolve->topoSort());
25 }

 

  • dll测试

  1 TEST_METHOD(Test_1)             // -w
  2 {
  3     char* words[] = {
  4         "ab",
  5         "accccccccccccccccccccc",
  6         "ad",
  7         "bc",
  8         "bd",
  9         "cd",
 10     };
 11     char* chain[100];
 12     char* ans[] = {
 13         "ab", "bc", "cd"
 14     };
 15     Assert::AreEqual(3, gen_chain_word(words, 6, chain, 0, 0, false));
 16     Assert::AreEqual(0, strcmp(chain[0], ans[0]));
 17     Assert::AreEqual(0, strcmp(chain[1], ans[1]));
 18     Assert::AreEqual(0, strcmp(chain[2], ans[2]));
 19 }
 20  21 TEST_METHOD(Test_2)             // -c
 22 {
 23     char* words[] = {
 24         "ab",
 25         "accccccccccccccccccccc",
 26         "ad",
 27         "bc",
 28         "bd",
 29         "cd",
 30     };
 31     char* chain[100];
 32     char* ans[] = {
 33         "accccccccccccccccccccc", "cd"
 34     };
 35     Assert::AreEqual(2, gen_chain_char(words, 6, chain, 0, 0, false));
 36     Assert::AreEqual(0, strcmp(chain[0], ans[0]));
 37     Assert::AreEqual(0, strcmp(chain[1], ans[1]));
 38 }
 39  40 TEST_METHOD(Test_3)             // -w -h
 41 {
 42     char* words[] = {
 43         "ab",
 44         "accccccccccccccccccccc",
 45         "ad",
 46         "bc",
 47         "bdddd",
 48         "cd",
 49     };
 50     char* chain[100];
 51     char* ans[] = {
 52         "bc", "cd"
 53     };
 54     Assert::AreEqual(2, gen_chain_word(words, 6, chain, 'b', 0, false));
 55     Assert::AreEqual(0, strcmp(chain[0], ans[0]));
 56     Assert::AreEqual(0, strcmp(chain[1], ans[1]));
 57 }
 58  59 TEST_METHOD(Test_4)             // -c -h
 60 {
 61     char* words[] = {
 62         "ab",
 63         "accccccccccccccccccccc",
 64         "ad",
 65         "bc",
 66         "bdddd",
 67         "cd",
 68         "dd",
 69     };
 70     char* chain[100];
 71     char* ans[] = {
 72         "bdddd", "dd"
 73     };
 74     Assert::AreEqual(2, gen_chain_char(words, 7, chain, 'b', 0, false));
 75     Assert::AreEqual(0, strcmp(chain[0], ans[0]));
 76     Assert::AreEqual(0, strcmp(chain[1], ans[1]));
 77 }
 78  79 TEST_METHOD(Test_5)             // -w -t
 80 {
 81     char* words[] = {
 82         "ab",
 83         "accccccccccccccccccccc",
 84         "ad",
 85         "bc",
 86         "bdddd",
 87         "cd",
 88     };
 89     char* chain[100];
 90     char* ans[] = {
 91         "ab", "bc"
 92     };
 93     Assert::AreEqual(2, gen_chain_word(words, 6, chain, 0, 'c', false));
 94     Assert::AreEqual(0, strcmp(chain[0], ans[0]));
 95     Assert::AreEqual(0, strcmp(chain[1], ans[1]));
 96 }
 97  98 TEST_METHOD(Test_6)             // -c -t
 99 {
100     char* words[] = {
101         "ab",
102         "accccccccccccccccccccc",
103         "ad",
104         "bc",
105         "bdddd",
106         "cd",
107         "cc"
108     };
109     char* chain[100];
110     char* ans[] = {
111 "accccccccccccccccccccc", "cc"
112     };
113 Assert::AreEqual(2, gen_chain_char(words, 7, chain, 0, 'c', false));
114 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
115 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
116 }
117 118 TEST_METHOD(Test_7)// -w -h -t
119 {
120 char* words[] = {
121 "ab",
122 "accccccccccccccccccccc",
123 "ad",
124 "ae",
125 "bc",
126 "bdddd",
127 "be",
128 "cd",
129 "ce",
130 "de"
131     };
132 char* chain[100];
133 char* ans[] = {
134 "bc", "cd"
135     };
136 Assert::AreEqual(2, gen_chain_word(words, 10, chain, 'b', 'd', false));
137 138 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
139 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
140 }
141 142 TEST_METHOD(Test_8)// -c -h -t
143 {
144 char* words[] = {
145 "ab",
146 "accccccccccccccccccccc",
147 "ad",
148 "ae",
149 "bc",
150 "bdddd",
151 "be",
152 "cd",
153 "ce",
154 "de",
155 "dd",
156     };
157 char* chain[100];
158 char* ans[] = {
159 "bdddd", "dd"
160     };
161 Assert::AreEqual(2, gen_chain_char(words, 11, chain, 'b', 'd', false));
162 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
163 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
164 }
165 166 TEST_METHOD(Test_9)// -w  but have ring
167 {
168 char* words[] = {
169 "ab",
170 "accccccccccccccccccccc",
171 "ad",
172 "ae",
173 "bc",
174 "bdddd",
175 "db",
176 "be",
177 "cd",
178 "ce",
179 "de"
180     };
181 char* chain[100];
182 Assert::AreEqual(-4, gen_chain_word(words, 11, chain, 0, 0, false));
183 }
184 185 TEST_METHOD(Test_10)// -c but have ring
186 {
187 char* words[] = {
188 "ab",
189 "accccccccccccccccccccc",
190 "ad",
191 "ae",
192 "bc",
193 "bdddd",
194 "db",
195 "be",
196 "cd",
197 "ce",
198 "de"
199     };
200 char* chain[100];
201 Assert::AreEqual(-4, gen_chain_char(words, 11, chain, 0, 0, false));
202 }
203 204 TEST_METHOD(Test_11)// -w have self
205 {
206 char* words[] = {
207 "ab",
208 "accccccccccccccccccccc",
209 "ad",
210 "ae",
211 "bb",
212 "bc",
213 "bdddd",
214 "be",
215 "cc",
216 "cd",
217 "ce",
218 "dd",
219 "de"
220     };
221 char* chain[100];
222 char* ans[] = {
223 "ab", "bb", "bc", "cc", "cd", "dd", "de"
224     };
225 Assert::AreEqual(7, gen_chain_word(words, 13, chain, 0, 0, false));
226 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
227 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
228 Assert::AreEqual(0, strcmp(chain[2], ans[2]));
229 Assert::AreEqual(0, strcmp(chain[3], ans[3]));
230 Assert::AreEqual(0, strcmp(chain[4], ans[4]));
231 Assert::AreEqual(0, strcmp(chain[5], ans[5]));
232 Assert::AreEqual(0, strcmp(chain[6], ans[6]));
233 }
234 235 TEST_METHOD(Test_12) {// -c have self
236 char* words[] = {
237 "ab",
238 "accccccccccccccccccccc",
239 "ad",
240 "ae",
241 "bb",
242 "bc",
243 "bdddd",
244 "be",
245 "cc",
246 "cd",
247 "ce",
248 "dd",
249 "de"
250     };
251 char* chain[100];
252 char* ans[] = {
253 "accccccccccccccccccccc", "cc", "cd", "dd", "de"
254     };
255 Assert::AreEqual(5, gen_chain_char(words, 13, chain, 0, 0, false));
256 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
257 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
258 Assert::AreEqual(0, strcmp(chain[2], ans[2]));
259 Assert::AreEqual(0, strcmp(chain[3], ans[3]));
260 Assert::AreEqual(0, strcmp(chain[4], ans[4]));
261 }
262 263 TEST_METHOD(Test_13)// -w -r
264 {
265 char* words[] = {
266 "ab", "aaaaabbbbbccccc", "aaaaaddddd",
267 "bc",
268 "cb", "cd",
269     };
270 char* chain[100];
271 char* ans[] = {
272 "aaaaabbbbbccccc", "cb", "bc", "cd"
273     };
274 Assert::AreEqual(4, gen_chain_word(words, 6, chain, 0, 0, true));
275 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
276 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
277 Assert::AreEqual(0, strcmp(chain[2], ans[2]));
278 Assert::AreEqual(0, strcmp(chain[3], ans[3]));
279 }
280 281 TEST_METHOD(Test_14) {// -c -r
282 char* words[] = {
283 "ab", "aaaccc", "aaaaabbbbbcccccddddd",
284 "bc",
285 "cb", "cd",
286 "dd",
287     };
288 char* ans[] = {
289 "aaaaabbbbbcccccddddd", "dd"
290     };
291 char* chain[100];
292 Assert::AreEqual(2, gen_chain_char(words, 7, chain, 0, 0, true));
293 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
294 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
295 }
296 297 TEST_METHOD(Test_15) {// -w -r -h -t
298 char* words[] = {
299 "ab",
300 "bccccccccccccccccccccccccccc", "bd",
301 "cd",
302 "da", "dc",
303     };
304 char* ans[] = {
305 "bd", "dc", "cd", "da"
306     };
307 char* chain[100];
308 Assert::AreEqual(4, gen_chain_word(words, 6, chain, 'b', 'a', true));
309 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
310 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
311 Assert::AreEqual(0, strcmp(chain[2], ans[2]));
312 Assert::AreEqual(0, strcmp(chain[3], ans[3]));
313 }
314 315 TEST_METHOD(Test_16) {// -c -r -h
316 char* words[] = {
317 "ab",
318 "bccccccccccccccccccccccccccc", "bd",
319 "cd",
320 "da", "dc",
321     };
322 char* ans[] = {
323 "bccccccccccccccccccccccccccc","cd", "da"
324     };
325 char* chain[100];
326 Assert::AreEqual(3, gen_chain_char(words, 6, chain, 'b', 'a', true));
327 Assert::AreEqual(0, strcmp(chain[0], ans[0]));
328 Assert::AreEqual(0, strcmp(chain[1], ans[1]));
329 Assert::AreEqual(0, strcmp(chain[2], ans[2]));
330 }

 

如下是测试时代码覆盖率及测试结果。

 

 


计算模块部分异常处理说明

  • 异常种类:

    • 输入输出单词表有效性

    • 参数(head、tail)有效性

    • 无环状况搜索到环

    • 未搜索到单词链

  • 异常测试:

    • 输入输出单词表有效性测试

     1 TEST_METHOD(Test_1)
     2     {
     3       char* words[] = {
     4         NULL,
     5         NULL,
     6         "ad",
     7         "bc",
     8         "bd",
     9         "cd",
    10       };
    11       char* chain[100];
    12       Assert::AreEqual(-3, gen_chain_word(words, 6, chain, 0, 0, false));
    13     }

     

    • 参数有效性测试

     1 TEST_METHOD(Test_2)
     2     {
     3         char* words[] = {
     4             "ab",
     5             "accccccccccccccccccccc",
     6             "ad",
     7             "bc",
     8             "bd",
     9             "cd",
    10         };
    11         char* chain[100];
    12         Assert::AreEqual(-1, gen_chain_word(words, 6, chain, '-', 0, false));
    13     }
    14 15     TEST_METHOD(Test_3)
    16     {
    17         char* words[] = {
    18             "ab",
    19             "accccccccccccccccccccc",
    20             "ad",
    21             "bc",
    22             "bd",
    23             "cd",
    24         };
    25         char* chain[100];
    26         Assert::AreEqual(-2, gen_chain_word(words, 6, chain, 0, '-', false));
    27     }
    • 环识别测试

     1 TEST_METHOD(Test_6)
     2     {
     3         char* words[] = {
     4             "ab",
     5             "accccccccccccccccccccc",
     6             "ba",
     7         };
     8         char* chain[100];
     9         Assert::AreEqual(-4, gen_chain_word(words, 3, chain, 0, 0, false));
    10     }
    • 未搜索到单词链测试

     1 TEST_METHOD(Test_4)
     2     {
     3         char* words[] = {
     4             "ab",
     5             "accccccccccccccccccccc",
     6             "ad",
     7         };
     8         char* chain[100];
     9         Assert::AreEqual(-5, gen_chain_word(words, 3, chain, 0, 0, false));
    10     }

界面模块设计

界面模块设计主要采用C++的 QT模块,利用QT creator 先设计好主要的GUI界面以后,导出代码,而后针对每一个控件编写相应的响应函数。GUI 实在64位的编译环境下编写,主要支持功能时直接输入框输入单词,和用户交互式的导入文本文件,也支持将程序运行的结果导出到用户指定文件中。

模块主要界面以下:

 

 

其中主要的功能函数绑定在openfile writefile 以及 run 三个Button 上,界面代码以下:

 1  void gui(QMainWindow *MainWindow)
 2     {
 3         if (MainWindow->objectName().isEmpty())
 4             MainWindow->setObjectName(QStringLiteral("MainWindow"));
 5         MainWindow->resize(661, 397);
 6         centralWidget = new QWidget(MainWindow);
 7         centralWidget->setObjectName(QStringLiteral("centralWidget"));
 8         //centralWidget = MainWindow;
 9         textBrowser = new QTextBrowser(centralWidget);
10         textBrowser->setObjectName(QStringLiteral("textBrowser"));
11         textBrowser->setGeometry(QRect(300, 50, 201, 221));
12         textBrowser_2 = new QTextEdit(centralWidget);
13         textBrowser_2->setObjectName(QStringLiteral("textBrowser_2"));
14         textBrowser_2->setGeometry(QRect(10, 50, 201, 221));
15         checkBox = new QCheckBox(centralWidget);
16         checkBox->setObjectName(QStringLiteral("checkBox"));
17         checkBox->setGeometry(QRect(540, 40, 71, 16));
18         checkBox_2 = new QCheckBox(centralWidget);
19         checkBox_2->setObjectName(QStringLiteral("checkBox_2"));
20         checkBox_2->setGeometry(QRect(540, 60, 71, 16));
21         checkBox_3 = new QCheckBox(centralWidget);
22         checkBox_3->setObjectName(QStringLiteral("checkBox_3"));
23         checkBox_3->setGeometry(QRect(540, 80, 71, 16));
24         checkBox_4 = new QCheckBox(centralWidget);
25         checkBox_4->setObjectName(QStringLiteral("checkBox_4"));
26         checkBox_4->setGeometry(QRect(540, 100, 71, 16));
27         checkBox_5 = new QCheckBox(centralWidget);
28         checkBox_5->setObjectName(QStringLiteral("checkBox_5"));
29         checkBox_5->setGeometry(QRect(540, 20, 71, 16));
30         textEdit = new QLineEdit(centralWidget);
31         textEdit->setObjectName(QStringLiteral("textEdit"));
32         textEdit->setGeometry(QRect(540, 140, 30, 30));
33         textEdit_2 = new QLineEdit(centralWidget);
34         textEdit_2->setObjectName(QStringLiteral("textEdit_2"));
35         textEdit_2->setGeometry(QRect(580, 140, 30, 30));
36         label = new QLabel(centralWidget);
37         label->setObjectName(QStringLiteral("label"));
38         label->setGeometry(QRect(540, 120, 31, 20));
39         label_2 = new QLabel(centralWidget);
40         label_2->setObjectName(QStringLiteral("label_2"));
41         label_2->setGeometry(QRect(580, 120, 31, 20));
42         pushButton = new QPushButton(centralWidget);
43         pushButton->setObjectName(QStringLiteral("pushButton"));
44         pushButton->setGeometry(QRect(70, 10, 75, 23));
45         pushButton_2 = new QPushButton(centralWidget);
46         pushButton_2->setObjectName(QStringLiteral("pushButton_2"));
47         pushButton_2->setGeometry(QRect(360, 10, 75, 23));
48         pushButton_3 = new QPushButton(centralWidget);
49         pushButton_3->setObjectName(QStringLiteral("pushButton_3"));
50         pushButton_3->setGeometry(QRect(220, 130, 75, 23));
51         MainWindow->setCentralWidget(centralWidget);
52         menuBar = new QMenuBar(MainWindow);
53         menuBar->setObjectName(QStringLiteral("menuBar"));
54         menuBar->setGeometry(QRect(0, 0, 661, 23));
55         MainWindow->setMenuBar(menuBar);
56         mainToolBar = new QToolBar(MainWindow);
57         mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
58         MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
59         statusBar = new QStatusBar(MainWindow);
60         statusBar->setObjectName(QStringLiteral("statusBar"));
61         MainWindow->setStatusBar(statusBar);
62         retranslateUi(MainWindow);
63 64         QMetaObject::connectSlotsByName(MainWindow);
65     } // setupUi

一、openfie

该 button 绑定了导入输入文件的函数,能够方便让用户直接导入本身的输入数据,代码实现以下:

 1 void MainWindow::openfile()
 2 {
 3  4   QString fileName = QFileDialog::getOpenFileName(this,tr("choose log"),"",tr("TXT(*.txt)"));
 5   if (fileName.isEmpty())
 6       return;
 7   QFile file(fileName);
 8   if (file.open(QIODevice::ReadOnly | QIODevice::Text))
 9   {
10       while (!file.atEnd())
11       {
12 13           QByteArray line = file.readLine();
14           QString str(line);
15 16           //qDebug() << str;;
17           this->textBrowser_2->insertPlainText(str);
18       }
19 20       file.close();
21   }
22 23 }

二、writefile

该 button 绑定了导入结果数据的函数,能够方便让用户直接导出函数的运行结果,代码实现以下:

 1 void MainWindow::writefile()
 2 {
 3  4   QString fileName = QFileDialog::getOpenFileName(this,tr("choose log"),"",tr("TXT(*.txt)"));
 5   if (fileName.isEmpty())
 6       return;
 7   QFile file(fileName);
 8   if (file.open(QIODevice::ReadOnly | QIODevice::Text))
 9   {
10       while (!file.atEnd())
11       {
12 13           QByteArray line = file.readLine();
14           QString str(line);
15 16           //qDebug() << str;;
17           this->textBrowser_2->insertPlainText(str);
18       }
19 20       file.close();
21   }
22 23 }

三、run

该button绑定的函数调用了Core.dll中的函数,实现了对数据的处理与计算。代码以下:

 1 void MainWindow::run()
 2 {
 3     QLibrary mylib("Core.dll");
 4     mylib.load();
 5      //加载动态库
 6      if (!mylib.isLoaded())
 7      {
 8          qDebug()<<QString("Load Oracle oci.dll failed!\n");
 9          return ;
10      }
11     p_gen_chain_word get_chain_word=(p_gen_chain_word)mylib.resolve("gen_chain_word");
12     p_gen_chain_char get_chain_char=(p_gen_chain_char)mylib.resolve("gen_chain_char");
13     char head = '\0',end = '\0';
14     char* words[10000];
15     char* result[10000];
16     bool b_w = this->checkBox->isChecked()==true;
17     bool b_c = this->checkBox_2->isChecked()==true;
18     bool b_h = this->checkBox_3->isChecked()==true;
19     bool b_t = this->checkBox_4->isChecked()==true;
20     bool b_r = this->checkBox_5->isChecked()==true;
21     if(b_w && b_c)
22     {
23         QMessageBox:: information(NULL,"Error","can't choose w and c at the same time");
24         return;
25     }
26     if(!b_w && !b_c)
27     {
28         QMessageBox:: information(NULL,"Error","need a w or cs");
29         return;
30     }
31     if(b_h)
32     {
33         QByteArray head_text = this->textEdit->text().toLower().toLatin1();
34         head = head_text.data()[0];
35         if(!(head>='a' && head <='z'))
36         {
37             QMessageBox:: information(NULL,"Error","head must in a-z");
38             return;
39         }
40 41     }
42     if(b_t)
43     {
44         QByteArray head_text = this->textEdit_2->text().toLower().toLatin1();
45         end = head_text.data()[0];
46         if(!(head>='a' && head <='z'))
47         {
48             QMessageBox:: information(NULL,"Error","tail must in a-z");
49             return;
50         }
51 52     }
53 54     QStringList text = this->textBrowser_2->toPlainText().split("\n");
55     int len = 0;
56     int word_num = String2Char(text,words);
57     if(b_w)
58     {
59         len = get_chain_word(words,word_num,result,head,end,b_r);
60     }
61     if(b_c)
62     {
63         len = get_chain_char(words,word_num,result,head,end,b_r);
64     }
65     if(len<=1)
66     {
67         if(len == -4)
68         {
69             QMessageBox:: information(NULL,"Error","shouldn't have circles");
70             return;
71         }
72         if(len == -5)
73         {
74             QMessageBox:: information(NULL,"Error","Chain don't exist");
75             return;
76         }
77         QMessageBox:: information(NULL,"Error","unkown error! please input valid data");
78         return;
79     }
80     qDebug()<<len;
81     int i;
82     this->textBrowser->clear();
83     for(i = 0;i<len;i++)
84     {
85         string a(result[i]);
86         this->textBrowser->append(QString::fromStdString(a));
87         qDebug()<<QString::fromStdString(a);
88     }
89 }

界面模块与计算模块对接

笔者小组同其余小组(16061161-15231112组和16061093-16061155组)进行了计算模块dll的交换。因为两个小组在项目开始前就对接口部分进行了讨论,在接口各参数、返回值以及功能上达成了共识,即计算接口设计部分所述。因为完成全部模块的设计及dll打包后,笔者在本小组的测试程序以及GUI上对dll进行了导入测试,在进入与其余小组对接阶段时并未遇到严重BUG,但在这过程当中也遇到了一些小问题。

  • 打包dll和GUI模块所支持处理器不一样。 在最初打包dll时未注意X86和X64以及Debug和Release版本间的区别,打包出错误版本的dll,致使GUI没法导入dll。在复核了版本后就解决了这一问题。

  • 异常处理问题。 笔者小组采用Qt Creater进行GUI部分的开发,然后端进行Visual Studio进行开发。前者对于dll抛出异常的支持较差,容易致使程序出错。在采用返回值返回错误信息的方式后解决了这一问题。

 

             

  

            

 

开发过程总览

在结对以前,笔者和结对伙伴就已经认识,但从未在程序开发上进行合做。本次结对编程应当是小组两人第一次合做开发。如下是按照项目开发的里程碑来总览笔者小组开发的历程。

  • 启动题目 在结对题目刚出来时,咱们很快就在一块儿对需求进行了讨论,很快就列出了最初的项目设计以及日程计划,开始了项目的推动。因为其余课程以及实验室任务等缘由,咱们并无不少公共的时间进行结对开发,仅有天天晚上用大约6小时左右的时间一同编程。

  • 完成第一版 在项目启动后约两天,咱们就按照最初的设计(设计见性能改进部分)实现了程序的基本功能。在实现的过程当中,笔者按照单元测试的编写要求,编写并进行了单元测试,完成了初版的测试集,供后期回归测试使用。

  • 优化算法 因为最初的设计的时间复杂度较高,咱们在完成第一版的测试后便进入了算法的改进和优化的阶段。笔者将部分的功能改成使用动态规划算法实现,并根据搜索单词链的要求设计了不一样的递推式。笔者的搭档将第一版的深度搜索进行了优化以补充动态规划未涉及的功能。通过了约4天,咱们基本完成了算法的优化,开始了新测试的编写以及进行回归测试。

  • GUI开发和核心代码封装 在算法优化的后半阶段,咱们开始了GUI部分的同步开发以及计算模块的封装。这一部分是咱们整个开发过程当中最为艰难的阶段。咱们在Qt环境的配置、dll的打包及使用上遇到了不少困难。主要在于dll相似于黑盒,咱们在测试其是否打包成功并加载入Qt是耗费了不少时间。

  • 终版完成 最终通过了两周的结对编程,笔者和搭档较好的完成了最长单词链的程序。在这过程当中,因为是第一次结对编程前期的效率并不高。直到进入了优化阶段,咱们在逐渐找到告终对编程的节奏,最终使用了约2000分钟完成了项目。

 

 

 

总结

结对编程优缺点

通过长达两周的结对编程,结合《构建之法》中对结对编程的描述以及这两周的亲身经历,笔者对于结对编程的优缺点有了如下的感想。

优势

  • 更容易定位Bug 结对编程过程当中,两我的共同看一份代码,极大的解决了两我的分工合做致使的代码bug 定位困难的问题,两我的在一块儿编程,总有一我的能够快速的定位到bug 的位置。

  • 能够设计出更好的方法 俗话说三个臭皮匠,顶个诸葛亮,在结对编程中,两我的一块儿思考算法,总结出的解决问题的方法每每会比一我的想出来的更严谨也更高效。让程序的总体性能上也获得了提高。

  • 沟通方便 结对编程,两我的坐在一块儿编程,沟通起来也是十分的方便,不只很好的避免了两我的在沟通上容易产生的误解,也极大的减小了沟通所用的时间,很大程度上节省了没必要要的争执,与误解致使的时间上的狼浪费。

缺点

  • 进度会被减慢 由于结对开发不是两我的的并行开发,因此必定程度上的减慢了项目总体推动的效率,致使整个工做周期被大大的延长。

结对编程反思

通过了两周的合做,笔者对本身和队友在结对编程中各自的亮点和不足进行了一下总结。

队员 优势 不足
笔者 1.吃苦耐劳 2.善于接受新知识 3.积极沟通 不善于撰写报告,以及进行程序测试
队友 1.代码编写规范 2.善于写测试用例 3.善于封装程序 不能熬夜