301
社区成员
发帖
与我相关
我的任务
分享第三单元聚焦于JML规格,在算法方面的要求较前两个单元有所下降,但规格与实现相分离的软件设计原则也导致了一定的区分度,也给了我们不少发挥的空间。
此外,每次作业都需要对特定方法编写一个Junit测试方法。
本单元的架构均来自于课程组已经给定的JML,仅在实现上有些许不同。
本单元的问题实际上是图论问题。Network作为一张大图,Person类就是图的顶点,而Acquaintance类似于边。
通过阅读JML规格的描述,我采用了临界矩阵来存储图,为了优化性能大量使用HashMap作为容器。对于一些特定数据,如每个person的messages需要有头部插入的功能,我选择了链表以达到O(1)。以上是数据结构方面的优化,算法方面的优化如下:
最短路算法的实现有不少,我们注意到本次作业中的边权始终为1,故采用bfs以O(n)的时间复杂度解决即可
public int bfsPath(Person from, Person to, ArrayList<Person> bfsTrack) {
ArrayList<Person> bfsQueue = new ArrayList<>();
((MyPerson) from).setFlag(true);
bfsQueue.add(from);
while (!bfsQueue.isEmpty()) {
MyPerson newFrom = (MyPerson) bfsQueue.get(0);
int dis = newFrom.getDis();
for (Person person : newFrom.getAcquaintance()) {
if (person.equals(to)) {
return dis + 1;
}
MyPerson myPerson = (MyPerson) person;
if (!myPerson.getFlag()) {
myPerson.setFlag(true);
myPerson.setDis(dis + 1);
bfsQueue.add(person);
}
}
bfsTrack.add(bfsQueue.get(0));
bfsQueue.remove(0);
}
return 999999;
}
我建立了Block这个类来作为连通块,主要的复杂度集中在删边时重新确定连通块上,代码如下:
public void split(Person person1, Person person2) {
int homeBlock = person2Block.get(person1);
MyPerson from = (MyPerson) person1;
MyPerson to = (MyPerson) person2;
for (Person person : block2Persons.get(homeBlock)) {
((MyPerson) person).setFlag(false);
}
ArrayList<Person> bfsTrack = new ArrayList<>();
if (!bfs(from, to, bfsTrack)) {
blockId++;
blockNum++;
block2Persons.put(blockId, new HashSet<>());
for (Person person : bfsTrack) {
block2Persons.get(homeBlock).remove(person);
block2Persons.get(blockId).add(person);
person2Block.replace(person, blockId);
}
}
}
JML规格中对于查询方法的复杂度达到了O(n),O(n^2)乃至O(n^3),为了不超时,将查询复杂度分摊到每一次增删上以保证最坏时间复杂度,是一个很自然的想法。相关的属性有ValueSum TripleSum Iscircle等。
契约式设计是一种软件设计方法,它将程序中的规格(契约)与实现(代码)分离开来。在契约式程序设计中,规格是描述组件、函数或类的预期行为的明确约定,而实现是代码的具体实现细节。
这个原则实际上我们经常接触:做编程题时题目只给出了要求完成的功能,没有限制实现的方法。我们可以认为这就是一种规格与实现相分离。
软件测试是指在软件开发过程中使用各种技术和工具对软件系统进行评估和验证的过程。它的目标是发现潜在的错误、缺陷或问题,并确保软件系统符合预期的质量标准和用户需求。
黑箱测试和白箱测试是软件测试中两种不同的方法。
黑箱测试(Black Box Testing)是一种测试方法,它关注于测试系统的功能和行为,而不考虑系统的内部结构和实现细节。测试人员在黑箱测试中没有访问代码、设计文档或内部知识,他们只关注于输入和输出之间的关系,以验证系统是否按照预期运行。黑箱测试侧重于检查软件是否符合规格说明、用户需求和预期功能。
白箱测试(White Box Testing),也被称为透明盒测试或结构测试,是一种测试方法,它关注于测试系统的内部结构、设计和实现细节。测试人员在白箱测试中可以访问代码、设计文档和内部知识,他们使用这些信息来设计和执行测试用例,以验证系统的内部逻辑是否正确。白箱测试侧重于覆盖代码路径、检查边界条件和错误处理机制,以确保软件在技术层面上是正确的。
数据构造是软件测试中一个重要的任务,它涉及生成测试数据以满足测试需求和覆盖测试目标。以下是一些常见的数据构造策略:
hw10_strong_1111.txt.本单元每次作业都针对了一个特定的函数编写JUnit测试。
需要对所有JML规格来编写测试代码,不能遗漏任何一个分支或变化或者不变。
由于直接面向JML来编写代码,JUnit测试可以有效保证方法满足契约的规范,也就是说经过检验的方法的正确性得到了保障。
前两次作业都均强测满分且未被Hack,可惜的是在第三次作业没有判断Tag的size导致出现了除0错误,也是我没有认真阅读JML并进行对照导致的。此外,由于互测数据规模限制,仅在第一次作业中采用大规模数据与多条查询指令把别人T了。
在这个单元中,我学习了JML规格的理解与实现,并应用它们来完成社交关系模拟系统的开发任务。这个单元的学习使我对JML规格的重要性和应用有了更深入的认识,并且提升了我的代码质量意识和能力。
通过学习JML规格,我意识到规格在软件开发中的关键作用。规格定义了组件的预期行为、约束条件和接口要求,能够明确地描述出组件应该如何正确使用和与其他组件交互。这为开发过程提供了清晰的指导,减少了开发人员对实现细节的依赖,提高了代码的可维护性和可扩展性。