2022面向对象第三单元总结

第三单元总结

测试方法和数据生成

测试方法

  • 采用黑盒测试
  • 测评机的实现较为简单,直接对拍即可

数据生成

随机数据

  • 分为 all, group, circle, message, emoji, money 六种模式
    • all:测试全部指令
    • group:测试与组相关的指令
    • circle:测试与关系相关的指令,重点是最小生成树和最短路
    • message:测试各种消息的发送和接受
    • emoji:测试表情类型消息的相关指令
    • money:测试红包类型消息的相关指令
  • 通过字典 INS_NUM_LIMIT = {'ap': 2500, 'qci': 100, 'ag': 20, 'qlc': 20, 'sim': 500} 限制各种指令的条数,可满足不同数据规模

特殊数据

  • 单指令:测试边界情况
  • 线性图、完全图等:测试 qlcsim 等指令的时间复杂度
  • 其他特征的数据:测试 qbsqgvsqgav 等指令的时间复杂度,具体特征各不相同,在这就不一一介绍了

数据有效性

  • 本人三次作业强测和互测均未被 hack
  • 三次互测均有 hack
  • 本次测出了其他同学的很多性能问题

架构分析

  • 核心类图(忽略了异常类和部分继承官方接口的类,重点关注图模型的构建与维护)

  • 类功能分析
    • Graph:关系图
      • 以联通分量 Block 为单位进行存储和维护
      • 支持 qbsqciqlcsim 等指令的查询
    • Block:联通分量
      • 保存了节点 MyPerson 和边 Relation 的信息
      • 用于计算最小生成树和最短路等
    • UnionFindSet:并查集
      • Graph 中用于 Block 的维护,在 Block 中用于 kruskal 算法求最小生成树
      • 进行了路径压缩、按大小合并等优化

性能问题与优化

输出性能问题

  • 在异常类中,使用 printf 函数输出会比 println 慢很多
  • 虽然不会影响通过测评,但是经过本地大规模数据的测试,在其他算法几乎相同的情况下,使用 printf 的总 CPU 时间能达到 println 的两倍

算法选择

  • 只要不出现 \(O(n^2)\) 复杂度的算法,通过强测和互测问题不大
  • qci:并查集 + 路径压缩 + 按大小合并
  • qlc:kruskal 算法(经本地测试,效率比堆优化的 prim 算法性能更好)
  • sim:dijkstra 算法 + 堆优化

动态维护

  • qgvs 为例,如果每次查询都重新计算一遍的话,复杂度会达到 \(O(n^2)\),因此可以进行动态维护
  • 添加 person 时,加上他与每个人的 value 值之和的两倍(删除时同理)
  • 添加 relation 时,遍历所有 group,如果两个人都在同一 group 中,加上 value

利用缓存

  • qlc 为例,在联通分量的结构不发生变化时,每次查询的结果一定相同,因此可以记录下来
  • 变量 leastConnection 记录最小生成树的路径权值和
    • 当其值不为 -1 时,表示数据有效,可直接返回
    • 否则需要重新计算最小生成树,并赋值给 leastConnection
  • 在添加 personrelation 时,将 leastConnection 设为 -1

Network 扩展

  • 新增 ProducerAdvertiserCustomer 接口并继承 Person

  • 新增 ItemMessage 接口并继承 Message,用于存储商品相关信息

  • 三个核心方法的规格如下

    /*@ public normal_behaviour
      @ requires !producer.hasItem(item);
      @ assignable producer.items;
      @ ensures producer.items.length = \old(producer.items.length) + 1;
      @ ensures producer.hasItem(item);
      @ ensures (\forall int i; 0 <= i && i < \old(producer.items.length);
      @         (\exists int j; 0 <= j && j < producer.items.length;
      @			producer.items[j] == (\old(producer.items[i]))));
      @ also 
      @ public exceptional_behaviour
      @ signals (DuplicatedItemException e) producer.hasItem(item);
      @*/
    void produce(Producer producer, ItemMessage item);
    
    /*@ public normal_behaviour
      @ requires !advertiser.hasItem(item) && producer.hasItem(item);
      @ assignable advertiser.items;
      @ ensures advertiser.items.length = \old(advertiser.items.length) + 1;
      @ ensures advertiser.hasItem(item);
      @ ensures (\forall int i; 0 <= i && i < \old(advertiser.items.length);
      @         (\exists int j; 0 <= j && j < advertiser.items.length;
      @			advertiser.items[j] == (\old(advertiser.items[i]))));
      @ also 
      @ public exceptional_behaviour
      @ signals (ItemNotFoundException e) !producer.hasItem(item);
      @ also 
      @ public exceptional_behaviour
      @ signals (DuplicatedItemException e) producer.hasItem(item) && advertiser.hasItem(item);
      @*/
    void advertise(Producer producer, Advertiser advertiser, ItemMessage item);
    
    
    /*@ public normal_behaviour
      @ requires advertiser.hasItem(item) && !customer.hasItem(item);
      @ assignable customer.items, advertiser.items;
      @ assignable customer.money, item.getProducer().money;
      @ ensures customer.items.length = \old(customer.items.length) + 1;
      @ ensures customer.hasItem(item);
      @ ensures (\forall int i; 0 <= i && i < \old(customer.items.length);
      @         (\exists int j; 0 <= j && j < customer.items.length;
      @			customer.items[j] == (\old(customer.items[i]))));
      @ ensures advertiser.items.length = \old(advertiser.items.length) - 1;
      @ ensures !advertiser.hasItem(item);
      @ ensures (\forall int i; 0 <= i && i < advertiser.items.length;
      @         (\exists int j; 0 <= j && j < \old(advertiser.items.length);
      @			advertiser.items[i] == (\old(advertiser.items[j]))));
      @ ensures customer.money = customer.money - item.getPrice();
      @ ensures item.getProducer().money = item.getProducer().money + item.getPrice();
      @ also 
      @ public exceptional_behaviour
      @ signals (ItemNotFoundException e) !advertiser.hasItem(item);
      @ also 
      @ public exceptional_behaviour
      @ signals (DuplicatedItemException e) advertiser.hasItem(item) && customer.hasItem(item);
      @*/
    void purchase(Advertiser advertiser, Customer customer, ItemMessage item);
    

心得与体会

  • 学习了 JML 的基础知识
  • 学会了如何用 JUnit 进行单元测试
  • 了解了契约式编程和防御式编程的概念
  • 复习了图相关算法
  • 数据构造能力进一步提升
posted @ 2022-06-04 18:39  t0ush1  阅读(45)  评论(0编辑  收藏  举报