BUAA_OO_2022 第三单元总结

OO Unit3 Blog

测试数据准备

首先是对相关jml的理解和解读,这一部分首先自己通读jml规格然后根据自己的理解写出代码。对于一些较为复杂的jml规格,与同学交流具体对应实现内容。

对于jml中的规格测试主要是对函数特殊边界情况的测试以及对大量数据的时间复杂度测试。

第三单元设计分析

第一次作业

第一次作业中主要的实现难点是并查集以及qbs指令的复杂度问题。其中并查集的相关实现较为简单,而对于qbs指令复杂度的问题,若使用传统的双重循环就会超时,较为巧妙的设计也是评论区中提到的设计方法就是使用一个常量times来存储这个值,找到引起times变化的两个条件并相应的变化就可正确得到相应值。

第二次作业

第二次作业中主要需要解决的是最小生成树算法问题。我使用的是kruskal算法,每次添加一条边对应的节点后循环找到需要添加的person,并添加到对应的set中,具体实现如下:

        while (peoples.size() != totalPeople.size()) {
           for (Person per : ((MyPerson)nowPer).getAcquaintances().keySet()) {
               if (!peoples.contains(per)) {
                   RelationSet relat = new RelationSet(nowPer.queryValue(per), per, nowPer);
                   relats.add(relat);
              }
          }
           relats.sort(new Comparator<RelationSet>() {
               @Override
               public int compare(RelationSet o1, RelationSet o2) {
                   if (o1.getValues() > o2.getValues()) {
                       return 1;
                  }
                   else if (o1.getValues() == o2.getValues()) {
                       return 0;
                  }
                   return -1;
              }
          });
           for (RelationSet relat : relats) {
               if (peoples.contains(relat.getPer1()) && peoples.contains(relat.getPer2())) {
                   continue;
              }
               if (peoples.contains(relat.getPer1())) {
                   peoples.add(relat.getPer2());
                   nowPer = relat.getPer2();
                   totalCount += relat.getValues();
                   break;
              }
               else {
                   peoples.add(relat.getPer1());
                   nowPer = relat.getPer1();
                   totalCount += relat.getValues();
                   break;
              }
          }
      }

需要注意的还是要保证实现的正确性。

第三次作业

这次主要实现的是最短路径算法,我采用dijkstra算法,但是在实现时只使用小数据测试程序没用使用大数据测试,导致一个地方少写了一个字母没有发现,在大数据测试时读取到NULL数据(悲),还是课下要多做测试。。对于堆优化部分可使用Java自带的优先队列实现对堆顶元素的读取,但是在删除堆顶元素后需要注意这个堆不会自动进行更新,这需要手动破坏当前状态使其更新堆顶元素。具体实现如下:

        PriorityQueue<Person> perPriQue = new PriorityQueue<>(new Comparator<Person>() {
           @Override
           public int compare(Person o1, Person o2) {
               return Integer.compare(((MyPerson) o1).getLeastLength(),
                      ((MyPerson) o2).getLeastLength());
          }
      });
       for (Person person : people.values()) {
          ((MyPerson)person).setLeastLength(maxNum);
      }
      ((MyPerson)per1).setLeastLength(0);
       perPriQue.addAll(people.values());
       MyPerson peekPerson = (MyPerson) perPriQue.poll(); // 弹出堆顶

       while (!peekPerson.equals(per2)) {
           okSets.put(peekPerson, peekPerson.getLeastLength());
           HashMap<Person, Integer> acqs = peekPerson.getAcquaintances();
           for (Person per : acqs.keySet()) {
               if (!okSets.containsKey(per) && (((MyPerson) per).getLeastLength() >
                      (peekPerson.getLeastLength() + acqs.get(per)))) {
                   perPriQue.remove(per);
                  ((MyPerson) per).setLeastLength(
                           peekPerson.getLeastLength() + acqs.get(per));
                   perPriQue.add(per);
              }
          }
           peekPerson = (MyPerson) perPriQue.poll();
      }
       if (peekPerson.equals(per2)) {
           return peekPerson.getLeastLength();
      }
       else {
           return 0;
      }

 

总体bug分析

这一单元总体bug体现为对实现方法的理解以及对方法复杂度的降低。前者需要能够熟练阅读jml代码从而获得相应实现内容,后者则需要自己探索较好的解决策略。都是可以避免的但还是犯下了错。

 

Network拓展

Network在拓展之后可以实现 购买商品、生产商品、发送广告、查询销售额、查询销售路径等方法。

需要添加 Advertiser、Producer、Customer这几个类

购买商品:

/*@ public normal_behavior
* @ requires getCustomer(customerId) != null && getAdvertiser(advertiserId) != null && (message instanceof PurchaseMessage);
* @ assignable getAdvertiser(advertiserId).getProducer(message.getProductId(productId));
* @
* @ ensures (\forall int i; 0 <= i && i < \old(getAdvertiser(advertiserId).getProducer(message.getProductId()).getMessageSize());
* @           getAdvertiser(advertiserId).getProducer(message.getProductId(productId)).getMessage(i + 1) ==
* @           \old(getAdvertiser(advertiserId).getProducer(message.getProductId(productId)).getMessage(i)));
* @ ensures getAdvertiser(advertiserId).getProducer(message.getProductId(productId)).getMessage(0) == message;
* @ ensures getAdvertiser(advertiserId).getProducer(message.getProductId(productId)).getMessageSize ==
* @         \old(getAdvertiser(advertiserId).getProducer(message.getProductId(productId)).getMessageSize) + 1;
* @ also
* @ public exceptional_behavior
* @ signals (CustomerIdNotFoundException e) !containsCustomer(customerId);
* @ signals (MessageTypeErrorException e) !(message instanceof PurchaseMessage);
* @ signals (AdvertiserIdNotFoundException e) !containsAdvertiser(advertiserId);
*/
public void purchaseItem(Message message, int customerId, int advertiserId, int productId);

广告信息发送:

/* @ public normal_behavior
* @ requires message instanceof AdvertiseMessage ;
* @ assignable customers.getAdvertisements, messages;
* @ ensures messages.length = \old(messages.length) - 1;
* @ ensures (\forall int i; 0 <= i && i < \old(messages.length) && messages.get(i) != message;
* @           (\exists int j; 0 <= j && j < messages.length; \old(messages.get(i)) == messages.get(j)));
* @ ensures (\forall int i; 0 <= i && i < customers.length; customers.getAdvertisements.get(\old(customers.getAdvertisements.size)) = message);
* @ ensures (\forall int i; 0 <= i && i < customers.length; customers.getAdvertisements.size == \old(customers.getAdvertisements.size) + 1);
* @ also
* @ puclic exceptional_behavior
* @ signal (MessageTypeErrorException e) !(message instanceof AdvertiseMessage);
*/
public void sendAdvertisement(Message message);

得到销售额:

/* @ public normal_behavior
* @ requires getAdvertiser(advertiseId) != null;
* @ ensures \result == getAdvertiser(advertiseId).getSalesMoney();
* @ also
* @ public exceptoinal_behavior
* @ signal (AdvertiserIdNotFoundException e) getAdvertiser(advertiseId) == null;
*/
public int getSalesMoney(int advertiserId);

学习体会

JML单元的学习让我了解到了契约式编程的准确和严谨,这对于方法的编写有着十分重要的指导作用,可做到精准。但是对于一些用数学语言表述十分简单的方法,用这种表述方式则十分繁琐,阅读理解的阻碍较大。当然jml只是给出了规范,需要自己整合优化相关实现。

posted @ 2022-06-06 10:56  tiderem  阅读(40)  评论(0编辑  收藏  举报