Object Oriented 2023 第二单元总结


前言

这个单元任务量很大,Bug 也很多,让人心累。不过呢确实学到了很多东西,从 Java 多线程,到 C++ 虚类,继承,多态,再到 Html,python flask,都可以有涉及。

本单元任务简介

第一次作业:本次作业的基本目标是模拟多线程实时电梯系统,熟悉线程的创建、运行等基本操作,熟悉多线程程序的设计方法。

第二次作业:在第一次作业的基础上,掌握线程安全知识并解决线程安全问题,同时在架构上围绕线程之间的协同设计层次架构。

第三次作业:在前两次作业的基础上,掌握线程之间的交互,强化线程之间的协同设计层次架构。

架构分析

Sequence Diagrams 时序图:

寻路算法分析

public static Route compute(Passenger p, ArrayList<Integer> accessList, int startAccess) {
    if (p.isArrived()) {
        return new Route(p, 0, 0); // already arrived
    }
    if (!canAccess(startAccess, p.getFrom())) {
        return new Route(p, 1000000000, 0); // cannot access
    }
    final ArrayDeque<VisitedFloor> deque = new ArrayDeque<>();
    if (canAccess(startAccess, p.getTo())) {
        return new Route(p, 1, 0); // directly
    } else {
        VisitedFloor first = new VisitedFloor(p.getFrom());
        ArrayList<Integer> arr = new ArrayList<>();
        for (int i = 1; i <= 11; i++) {
            if (!first.vis[i] && canAccess(startAccess, i)) {
                arr.add(i);
            }
        }
        arr.sort(Comparator.comparingInt(o -> Math.abs(o - p.getFrom())));
        for (int i : arr) { deque.add(new VisitedFloor(first, i)); }
    }
    while (!deque.isEmpty()) {
        final VisitedFloor cur = deque.poll();
        if (canAccess(accessList, cur.cur, p.getTo())) {
            return new Route(new Passenger(p.getId(), p.getFrom(), cur.first, p.getTo(), p),
                             cur.count + 1, cur.via);
        }
        for (int i = 1; i <= 11; i++) {
            if (!cur.vis[i] && canAccess(accessList, cur.cur, i)) {
                deque.add(new VisitedFloor(cur, i));
            }
        }
    }
    return new Route(p, 1000000000, 0); // cannot access
}

对每个请求,对每个电梯作为起始电梯进行广搜,返回乘坐该电梯需要的最小换乘次数以及到达所需楼层所要经过的楼层。

SystemController 中,按照一定的权重给每个电梯一个代价估值,然后选乘代价最小的电梯。为避免一个乘客在一个电梯中来回上下,我为乘客添加了曾经乘坐过的电梯队列,将乘坐过的电梯按照时间顺序依次抬高代价。

为避免静态分配导致后续加入的电梯没有任何工作可做,当电梯队列人数较多时,决定让新加入的乘客等待,延迟加入队列:

catch (ElevatorQueue.WaitException e) {
    new Thread(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } finally {
            Global.globalQueue.pushFront(passenger);
        }
    }).start();
}

不过这也是强测挂掉的原因。虽然有些奇怪,因为乘客数最多不会超过 100 人,所以依照此法开的线程数并不会太多。可能是强测波动原因导致新建线程被阻止而造成了乘客丢失,最后 RTLE。

Bugs

第一次作业因为二分查找写错了导致电梯请求队列变得无序,进而电梯接人策略出现严重问题,浪费大量时间,导致 RTLE。

第二次作业没有新的 Bug。

第三次作业因为开的线程过多被评测机禁止而导致乘客丢失,最后因为检测到请求未完成而一直等待已经丢失的东西而 RTLE。

互测刀中深搜写的复杂度过高而 CTLE 的。以及随缘写了一些代码而出现大面积漏洞 WA 的。

评测机

我搭建了一个线上的网页 “评测机”。准确来说,它并不是评测机,因为它只要求使用者上传对应输出,而无需上传源代码进行评测。

评测机网页前端搭建在 GitHub 我的博客上,当然这是因为可以借用我的博客的风格,不至于太简陋,另外也是免费的。

评测机评测后端位于 Mac Mini 上,使用 cpolar 进行了内网穿透。与前端通信使用的 Python + Flask,而评测使用的是 cpp 写的 checker。

评测机数据库位于 Leancloud,免费,而且有完备的 Python API,虽然有 API 调用次数限制,但是这样的小网站,想必是不可能超过限制的。

心得:学到很多东西,另外看到很多人使用也很有成绩感。当你不那么注重卷绩点或者分数的时候,多做做额外的工作,真的会很有收获。反对内卷,从我做起。

访问量

以下是单纯的成就感时间:

Lean Cloud API 访问次数统计:Lean Cloud API 访问次数统计

博客访问次数统计:Google Analytics

–fa6d2549c29453d3cdff08a8bbcddfde–

–f344bca0f555ef92c1d1da3b6867e934–


评论
  目录