BUAAOO-第三单元总结

Posted acsoto

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BUAAOO-第三单元总结相关的知识,希望对你有一定的参考价值。

BUAAOO-第三单元总结

实现规格所采取的设计策略

在第一次作业中,开始没有经验,采取了直接对规格进行“翻译”的策略,对数据保存直接使用了定长数组,后发现这样操作代码可读性不高且性能较差,于使重新改写为使用HashMap保存。

第二次作业中,虽然使用容器实现了数据存储,但是算法方面由于直接按照规格描述进行实现,导致了大量的CTLE。于使此后,阅读完规格后我能对方法有彻底理解后再根据自己的理解去实现。

再有以上经验后,认为实现规格应采取如下步骤:

  1. 完整阅读规格

  2. 选择正确的数据结构,容器

  3. 正确处理异常

  4. 选择合适的算法实现方法

基于JML规格来设计测试的方法和策略

  1. 再次阅读JML规格,检查在方法被实现前,异常是否被正确,处理检查方法是否满足规格的ensure

  2. 使用Junit,针对每一个具一定不确定因素的方法编写测试样例进行测试

  3. 对程序整体进行大数据集测试

本单元看似简单,但在测试方面我做的并不理想,在三次作业中均出现了非常低级的BUG

第一次:

原因是在阅读JML时并未彻底理解其含义,直接按照规格进行书写,导致进行了逻辑完全错误的一个判断

第二次:

低估了自己犯低级错误的的概率(当然本次作业主要问题在CTLE上)

第三次:

 

自作聪明在判断异常之前就删除了message,造成了大量WA

三次作业出现的bug基本都是在阅读JML规格时丧失理性造成的,事实证明在阅读JML时候一定要保证独立思考的能力,当然锅也不能全部甩到这里,归根结底还是自己懒得测试且高估了自己写简单代码不出错的能力

(Junit暴力测试?)

    @org.junit.jupiter.api.Test
   void sendIndirectMessage() throws EqualPersonIdException, PersonIdNotFoundException, EqualRelationException, MessageIdNotFoundException, EmojiIdNotFoundException, EqualMessageIdException, RelationNotFoundException, EqualEmojiIdException {
       Network network = new MyNetwork();
       network.addPerson(new MyPerson(1, "A", 10));
       network.addPerson(new MyPerson(3, "N", 10));
       network.addPerson(new MyPerson(6, "F", 10));
       network.addRelation(1, 3, 10);
       network.addRelation(3, 6, 15);
       network.addRelation(1, 6, 26);
       network.storeEmojiId(1);
       network.storeEmojiId(3);
       network.storeEmojiId(5);
       network.storeEmojiId(7);
       network.storeEmojiId(9);
       network.storeEmojiId(91);
       network.addMessage(new MyMessage(1, 10, network.getPerson(1), network.getPerson(6)));
       network.addMessage(new MyEmojiMessage(2, 1, network.getPerson(1), network.getPerson(6)));
       network.addMessage(new MyEmojiMessage(3, 1, network.getPerson(1), network.getPerson(6)));
       network.addMessage(new MyEmojiMessage(4, 1, network.getPerson(1), network.getPerson(6)));
       network.addMessage(new MyEmojiMessage(5, 3, network.getPerson(1), network.getPerson(6)));
       network.addMessage(new MyEmojiMessage(6, 9, network.getPerson(1), network.getPerson(6)));
       network.addMessage(new MyEmojiMessage(7, 91, network.getPerson(1), network.getPerson(6)));
       network.addMessage(new MyEmojiMessage(8, 91, network.getPerson(1), network.getPerson(6)));
       for (int i = 0; i < 8; i++) {
           network.sendMessage(i + 1);
      }
       assertEquals(4, network.deleteColdEmoji(1));
       assertEquals(true,network.containsEmojiId(91));
       network.deleteColdEmoji(3);
       assertEquals(false,network.containsEmojiId(91));
  }

容器选择和使用的经验

  1. 避免直接使用定长数组。

  2. 根据需求进行容器的选择,如果对象是通过ID来进行大部分操作,那么使用HashMap进行存储,如果对象如Person.messages,需要从头取出,从尾放入等操作,则使用ArrayList进行存储。适当的情景下也可使用Hashset来做集合的不重复性。

  3. 不确定要用什么的情况下,似乎还是用HashMap比较靠谱

性能问题

本次作业会出现的性能问题主要集中在容器的选择,qbs的算法,ageMean,ageVar等的算法。

对于容器的问题,我的避免超时的方法是采取了适合的容器如HashMap

我在第二次作业中大面积出现了性能问题(估计能踩的坑我都踩了)

  1. qbs的算法采用了规格描述的算法直接进计算,于使我对其进行了并查集算法的修改,在addPerson和delPerson的时候就对拥有同一个根节点的节点构成一个集合。(一开始还写了DFS,慢的要死就算了,还写了一堆BUG,忙一下午,服了。)

    private final HashMap<Integer, Integer> parent = new HashMap<>();
   private final HashMap<Integer, Integer> rank = new HashMap<>();


private int find(int id) {
       if (parent.get(id) != id) {
           parent.put(id, find(parent.get(id)));
      }
       return parent.get(id);
  }
   
   private void union(int id1, int id2) {
       int p = find(id1);
       int q = find(id2);
       if (p == q) {
           return;
      }
       if (rank.get(p) < rank.get(q)) {
           parent.put(p, q);
      } else if (rank.get(p) > rank.get(q)) {
           parent.put(q, p);
      } else {
           parent.put(p, q);
           rank.put(q, rank.get(q) + 1);
      }
  }

 

  1. ageMean,ageVar等的计算,起初我的计算直接采用了每次调用方法是从头开始计算的实现,结果导致每次计算要消耗大量的CPU超时,导致了CTLE,后改为在进行addperson的时候直接进行累加加和的操作,在询问ageMean的时候可以直接进行返回。

    private int ageSum = 0;
   private int ageMean = 0;
   private int ageVar = 0;
   private int valueSum = 0;
   @Override
   public void addPerson(Person person) {
       people.put(person.getId(), person);
       ageSum += person.getAge();
       ageMean = ageSum / people.size();
       ageVar = 0;
       for (Person p : people.values()) {
           ageVar += (p.getAge() - ageMean) * (p.getAge() - ageMean);
           if (p.isLinked(person)) {
               valueSum += p.queryValue(person) * 2;
          }
      }
       ageVar = ageVar / people.size();
  }
   @Override
   public void delPerson(Person person) {
       people.remove(person.getId());
       if (people.isEmpty()) {
           initialData();
           return;
      }
       ageSum -= person.getAge();
       ageMean = ageSum / people.size();
       ageVar = 0;
       for (Person p : people.values()) {
           ageVar += (p.getAge() - ageMean) * (p.getAge() - ageMean);
           if (p.isLinked(person)) {
               valueSum -= p.queryValue(person) * 2;
          }
      }
       ageVar = ageVar / people.size();
  }

 

架构设计

除了各个对象的HashMap以外,network维护一个并查集,group维护多个基本数据,在addPerson的能操作时进行各个数据的更新。

不知道写什么了,这单元挺搞心态的,对自己写BUG的能力又有了新的认识,因为自己时间不够能力不足,总做不好测试这一块,我也不知道怎么办,就尽力别写bug吧。不讲丧气话,这单元学到了JML规格相关知识,好像还是挺“严谨”的,如果以后工作或者什么遇到了,应该挺受益的,不过有一说一,我是不会愿意去自己写这个JML的,如果有中文版的JML能几句话讲清楚,那没准可以试试。

 

以上是关于BUAAOO-第三单元总结的主要内容,如果未能解决你的问题,请参考以下文章

BUAAOO 第三单元总结

BUAAOO第三单元总结

BUAAOO-第三单元总结-社交网络

BUAAOO第三单元总结

BUAAOO Unit3博客作业

BUAAOO 第四单元 & 课程总结