OO 第三单元总结

OO第三单元总结

一、测试数据构造

1、随机生成数据

本单元中,我编写了随机数据生成程序。在生成数据的过程中,我用了多个容器来管理已生成的合法 id 和已生成的合法关系,以保证在生成后续指令的时候有一定的概率生成已有的 id 或关系,代码示例如下

private int generateId(ArrayList<Integer> ids) {
    int ret;
    if (Math.abs(random.nextInt()) % 3 == 0 || ids.size() == 0) {
        ret = random.nextInt();
    } else {
        int index = Math.abs(random.nextInt()) % ids.size();
        ret = ids.get(index);
    }
    return ret;
}

其中,参数 ids 是管理不同种类 id 的容器,若要生成 personId,则传入管理 personId 的容器,若要生成 groupId,则传入管理 groupId 的容器。在这个方法中,我们使其有约为 1/3 的概率生成一个完全随机的 id,有约为 2/3 的概率生成一个已有的 id。在程序的其他地方,也采用类似的方法控制生成不同种类数据的概率,使其对 MyNetwrok 的覆盖率达到 100%。

2、针对性构造数据

根据不同方法的前置条件,针对性构造边界数据。例如可以构造没有边的图、退化成链的图等来测试图论算法的正确性。

二、架构设计

1、图的存储

我采用邻接表的方式存储图,在 Person 中存储与该 Person 直接相连的点的集合。

2、图论算法

  • 图的连通性:在维护图的同时,维护一个并查集。
  • 最小生成树:Prim 算法。
  • 最短路径:Dijkstra 算法。

三、性能问题和修复情况

本单元中产生的 bug 均为性能问题所致,具体如下

第二次作业

在 query_group_value_sum 中,我采用二重循环遍历计算,产生了 O(n^2) 的复杂度而导致运行超时。修复方案为维护一个 valueSum 变量,在加减人和增加关系的时候进行更新。

第三次作业

第三次作业采用了 O(n^2) 复杂度的 Dijkstra 算法而导致运行超时,修复方案为采用堆优化的 Dijkstra 算法,维护一个小顶堆,使复杂度降为 O(n log n) 。

四、Network 扩展

1、拓展方案

  • 新增三个类 Advertiser、Producer、Customer,均继承自 Person。
  • 新增 Advertisement 类,继承自 Message,用来表示广告。
  • 新增 PurchaseMessage 类,继承自 Message,用来表示购买消息。
  • 新增 product 类,用来表示产品。
  • 在 Network 中新增 postAdvertisement 方法,表示发布广告。
  • 在 Network 中新增 addProduct 方法,表示新增产品。
  • 在 Network 中新增 purchase 方法,表示购买产品,即发送 PurchaseMessage。

2、JML 规格

public interface Network {
    /*@ public instance model non_null Advertisement[] ads;
      @ public instance model non_null Product[] products;
      @*/

    //@ ensures \result == (\exists int i; 0 <= i && i < products.length; products[i].getId() == id);
    public /*@ pure @*/ boolean containsProduct(int id);

    /*@ public normal_behavior
      @ requires containsProduct(id);
      @ ensures (\exists int i; 0 <= i && i < products.length;
      @          products[i].getId() == id && \result == products[i]);
      @ also
      @ public normal_behavior
      @ requires !containsProduct(id);
      @ ensures \result == null;
      @*/
    public /*@ pure @*/ Product getProduct(int id);

    /*@ public normal_behavior
      @ requires containsMessage(id) && getMessage(id) instance of Advertisement;
      @ assignable messages, ads;
      @ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
      @         (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
      @         (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
      @ ensures ads.length == \old(ads.length) + 1;
      @ ensures (\forall int i; 0 <= i && i < \old(ads.length);
      @          (\exists int j; 0 <= j && j < ads.length; ads[j].equals(\old(ads[i]))));
      @ ensures (\exists int i; 0 <= i && i < ads.length; ads[i].getId() == id);
      @ also
      @ public exceptional_behavior
      @ signals (AdvertisementIdNotFoundException e) (!containsMessage(id)
      @                                               || !(getMessage(id) instanceof Advertisement));
      @*/
    public void postAdvertisement(int id) throws AdvertisementIdNotFoundException;

    /*@ public normal_behavior
      @ requires contains(producerId) && getPerson(producerId) instanceof Producer &&
      @          containsProduct(product.getId());
      @ assignable products;
      @ ensures products.length == \old(products.length) + 1;
      @ ensures (\forall int i; 0 <= i && i < \old(products.length);
      @          (\exists int j; 0 <= j && j < products.length; products[j] == \old(products[i])));
      @ ensures (\exists int i; 0 <= i && i < products.length; products[i] == product);
      @ also
      @ public exceptional_behavior
      @ signals (ProducerIdNotFoundException e) (!contains(producerId)
      @                                          || !(getPerson(producerId) instanceof Producer));
      @ signals (EqualProductIdException e) containsProduct(product.getId());
      @*/
    public void addProduct(int producerId, Product product) throws
            ProducerIdNotFoundException, EqualProductIdException;

    /*@ public normal_behavior
      @ requires containsMessage(id) && getMessage(id) instanceof PurchaseMessage;
      @ assignable messages;
      @ assignable products;
      @ assignable ((PurchaseMessage)getMessage(id)).buyer.money, ((PurchaseMessage)getMessage(id)).producer.money;
      @ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
      @         (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
      @         (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
      @ ensures !containsProduct(\old(((PurchaseMessage)getMessage(id)).productId)) && 
      @         products.length == \old(products.length) - 1 &&
      @         (\forall int i; 0 <= i && i < \old(products.length) &&
      @                         \old(products[i]).getId() != \old(((PurchaseMessage)getMessage(id)).productId);
      @          (\exists int j; 0 <= j && j < products.length; products[j] == products[i]));
      @ ensures ((PurchaseMessage)getMessage(id)).buyer.money == 
      @          \old(((PurchaseMessage)getMessage(id)).buyer.money) - ((PurchaseMessage)getMessage(id)).money;
      @ ensures ((PurchaseMessage)getMessage(id)).producer.money == 
      @          \old(((PurchaseMessage)getMessage(id)).producer.money) + \old(((PurchaseMessage)getMessage(id)).money);
      @ also
      @ public exceptional_behavior
      @ signals (PurchaseIdNotFoundException e) !containsMessage(id) || 
      @                                        !(getMessage(id) instanceof PurchaseMessage);
      @*/
    public void purchase(int id) throws PurchaseIdNotFoundException;
}

五、学习体会

本单元中我们学习了 JML,JML 能够准确地定义方法的行为,能让我们从逻辑的角度来验证代码实现的正确性。

在学习过程中,我感触最深的是照着 JML 能够很轻松的完成大部分方法,但是代码运行效率却不一定高,为了保证较低的时间复杂度,方法的实现方案还需我们自行设计。

posted @ 2022-06-05 22:14  wphos  阅读(28)  评论(0编辑  收藏  举报