301
社区成员
发帖
与我相关
我的任务
分享本单元是JML单元,相比前两次思维量少得多,是以博客内容也相应调整。
完全按照JML要求的架构
建立连通树
// MyNetwork 伪代码
private HashMap<Integer,Integer> toTreeEnd; //构造一个连通的树
public void addPerson():
toTreeEnd.put(person.getId(),null)
public void addRelation():
if (!(getEndPoint(id1) == getEndPoint(id2))):
toTreeEnd.put(getEndPoint(id1),getEndPoint(id2))
public int getEndPoint(int id):
while (toTreeEnd.get(end) != null) :
end = toTreeEnd.get(end)
// MyNetwork 伪代码
public void addPerson():
sumBlock++
public void addRelation():
if (!(getEndPoint(id1) == getEndPoint(id2))):
sumBlock--
//当需要删除关系时,进行深度优先搜索
// MyNetwork 伪代码
public void addRelation():
sumTriple += findCommon(id1,id2)
public void removeRelation():
sumTriple -= findCommon(id1,id2)
public int findCommon(int id1,int id2):
return sum: person that link id1 && link id2
广度优先搜索
//MyPerson
private long bestID = Long.MAX_VALUE;
private long maxVa = Long.MIN_VALUE;
public void buildLink(Person person, int value) {
……
if (value > maxVa) {
maxVa = value;
bestID = person.getId();
} else if (value == maxVa && person.getId() < bestID) {
bestID = person.getId();
}
}
public void removeLink(Person person) {
……
if (person.getId() == bestID) {
maxVa = Long.MIN_VALUE;
bestID = Long.MAX_VALUE;
if (acquaintance.size() != 0) {
for (Integer key:acquaintance.keySet()) {
Person p = acquaintance.get(key);
if (maxVa < value.get(p)) {
maxVa = value.get(p);
bestID = key;
} else if (maxVa == value.get(p) && acquaintance.get(key).getId() < bestID) {
bestID = acquaintance.get(key).getId();
}
}
}
}
}
public void addPerValue(Person person,int va) {
//参考上面两个,注意va可能是负数
}
//MyNetwork
public int queryCoupleSum() {
int ret = 0;
if (persons.size() == 0) {
return 0; }
for (Integer ieKey:persons.keySet()) {
MyPerson ieP = (MyPerson) persons.get(ieKey);
if (ieP.getAcquaintance().size() != 0) {
int j = ieP.findBestID();
MyPerson jeP = ((MyPerson) persons.get(j));
if (jeP.getAcquaintance().size() != 0) {
if (jeP.findBestID() == ieKey) { ret++; } } } }
ret /= 2;
return ret; }
本人在这一个点ctle后,使用了两个方法:
一个是设置脏位,来表示qtvs的上一次结果有没有可能被修改,如果没有变化,则直接返回上一次的结果.
否则进行遍历。而遍历方式也要修改:
jml要求
//Tag
/*@ ensures \result == (\sum int i; 0 <= i && i < persons.length;
@ (\sum int j; 0 <= j && j < persons.length &&
@ persons[i].isLinked(persons[j]); persons[i].queryValue(persons[j])));
@*/
public /*@ pure @*/ int getValueSum();
原来的遍历,好像和JML一模一样,emmmmmmm,不是JML让这么写的吗(气)
for (Integer ieKey:persons.keySet()):
for (Integer jeKey:persons.keySet()):
if (persons.get(jeKey).isLinked(persons.get(jekey))):
现在的遍历
for (Integer ieKey:persons.keySet()) :
for (Integer jeKey:((MyPerson) persons.get(ieKey)).getAcquaintance().keySet()) :
if (persons.get(jeKey) != null) :
想要保证性能,就不能照搬JML,而是要在满足JML规格的情况下进行性能的优化。也就是规格与实现结果相同,过程不同。
本单元中测强制要求进行单元测试,这也让我第一次详细了解了这一测试方法,感觉收益颇多。
前两次作业,本人都是构建一个复杂的图,然后调用需要测试的方法,然后对方法结果和其它变量是否被修改进行测试。
//public class MyNetworkTest
public MyNetwork myNetwork = null;//课程组的实现,调用测试方法,对照组
private OneNetwork oneNetwork = null;//本人的实现,调用测试方法,检测方法结果正确性
private MyNetwork yingZi = null;//课程组的实现,不调用测试方法,检测方法是否对不允许修改的变量进行修改
public void AssErt() throws PersonIdNotFoundException, RelationNotFoundException {
Person [] olds = yingZi.getPersons();
assertEquals(myNetwork.queryCoupleSum(),oneNetwork.queryCoupleSum());
Person [] news = myNetwork.getPersons();
assertEquals(olds.length,news.length);
for (int i = 0;i < olds.length;i++) {
boolean f = ((MyPerson) olds[i]).strictEquals(news[i]);
assertEquals(f,true);
}
}
一开始在思考第三单元是否有存在的必要,更何况五一期间还有作业,等写完了就没有再思考这个问题了。
这一单元相比前两个思维量比较小,大多数代码是翻译JML,但是翻译的时候也出现了许多问题,一个是没有及时更新JML,导致我有一个bug找了很久都没找到错误,后来才知道有个JML要修改,其次是翻译不是照搬,需要有自己的规格实现。