BUAA OO U3总结
单元图模型构建与维护
本单元要求根据规定好的JML规格实现一个模拟社交网络,该网络中包含了用户、标签、消息、公众号等多种对象类型,在其之间存在归属、关联等关系将其联系起来,形成一定规则下的复杂社交网络。
构建
在构建该社交网络编程实现时,我认为要保持一些意识:
- 建立关系时该关系作为一种映射是何种类型,如关系的一方是否可以归属于不同的另一方
- 两对象间存在的不同关系是否存在依赖关系,如本单元中Tag依赖于Relation
- 容器中的对象是否可以重复,是否是同一个对象
- 同一类的实例对象是否会由于不体现在继承实现层面的,而是体现在实例不同的归属关系导致其在不同层次上虽然代码判定(equals)相同但是在意义上并不相同,如不同Person可以有相同id的Tag,而这些Tag实例虽然equals,但在全局的Network来看,其意义并不是相同的。
维护
本单元进行的操作均为简单的增删查改,仍然要保持一些意识:
- 增加时注意相关的维护变量是否会由此发生改变,是否要在多个不同位置中添加
- 删除时注意维护变量,尤其是最值变量,删除时可能需要重新遍历寻找新的最值。同时注意是否删干净,删正确,在不同层次是否均删除,同一容器中多个该对象是否均删除,是否删除了在当前层次不该删除的对象。删除关系时还要注意会不会影响相关的依赖关系。
- 查找时能维护的变量可以通过存储变量来进行快速查询,减少频繁查询过程的耗费时间。
- 修改时注意维护变量是否变化,是否存在有依赖的对象需要修改。
性能与修复
本单元中存在性能问题的操作我认为只有查询和删除。相应的,查询导致的性能问题可以通过维护变量使其复杂度降低到常数级;删除导致的性能问题可以通过维护索引关系降低其时间复杂度(主要是通过哈希方法)。下面为一些查询和删除的实现思路实例。
查询连通性
可以通过并查集或者直接BFS实现
查询三元环
增加或删除关系时遍历当前所有人,判断是否存在三元环,维护三元环总数。
删除接收到的文章
自行构建容器储存接收的文章,用HashMap索引节点,节点构成双向链表,对双向链表进行维护。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| static class MyLinkedList<E> { private static class Node<E> { private E data; private Node<E> prev; private Node<E> next;
Node(E data) { this.data = data; } }
private final HashMap<E, HashSet<Node<E>>> indexMap = new HashMap<>(); private Node<E> head; private Node<E> tail;
public void addFirst(E e) { Node<E> newNode = new Node<>(e); if (head == null) { head = newNode; tail = newNode; } else { newNode.next = head; head.prev = newNode; head = newNode; } if (!indexMap.containsKey(e)) { indexMap.put(e, new HashSet<>()); } indexMap.get(e).add(head); }
public void remove(E e) { HashSet<Node<E>> set = indexMap.get(e); if (set == null) { return; } for (Node<E> node : set) { if (node.prev != null) { node.prev.next = node.next; } else { head = node.next; } if (node.next != null) { node.next.prev = node.prev; } else { tail = node.prev; } } indexMap.remove(e); }
public boolean contains(E e) { return indexMap.containsKey(e); }
public int size() { return this.toList().size(); }
public List<E> toList() { List<E> list = new ArrayList<>(); Node<E> current = head; while (current != null) { list.add(current.data); current = current.next; } return list; } }
|
总之,性能问题是本单元需要着重关心的问题之一,可以认为规格仅给出了正确性约束,而良好的性能则需要实现的过程中使用更好的方法。这里体现了规格和实现的分离。
测试
本单元中可以采用多种测试方法,单元测试可以通过JUnit这一工具对各个类的方法进行测试,保证方法层次的正确性。功能测试可以对社交网络中的一些简单功能进行测试。集成测试注重各个类之间的交互关系是否正确。这些方法在对自己的代码进行测试的过程中都是非常有效的。在互测环节,采用的策略主要是黑盒测试和压力测试,针对容易出错的地方,自行或AI辅助构造数据点,如大量删除文章,群组红包无法整除人数等。
大模型辅助
大模型可以很好地辅助JML这一单元的开发,第一次作业我直接将JML丢给大模型,生成的代码基本满足规格,但某些细节出现了问题,如删除关系时没有把联系人从Tag中删除。于是后面的作业我便没有全权交给大模型编写代码,而是把较为简单重复的部分交给其实现。
另一个方面可以利用大模型构造数据,以下使用的模型为claude-3.5-sonnet
1 2
| ......(互测数据限制) 以上是数据要求,当前项目为一个模拟社交网络,我希望你能帮我构造一些测试样例,如将一篇文章转给同一个人多次然后再删除该文章,给群组中的人发送不能被人数整除的面额的红包等多种情况
|
生成的数据样例最初存在参数错误的问题,经指正后便可以生成较为不错的数据样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
| 您说得对,我需要更准确地理解每个指令的参数。以下是基于Network类实现的正确测试样例:
text
Apply
ap 1 Zhang 20
ap 2 Li 21
ar 1 2 100
coa 1 3 Official
foa 2 3
ca 1 3 101
afm 1 101 1 2 0
sm 1
afm 2 101 2 1 0
sm 2
afm 3 101 1 2 0
sm 3
qra 2
da 1 3 101
afm 4 101 1 2 0
sm 4
qra 2
qrm 2
text
Apply
ap 1 Zhang 20
ap 2 Li 21
ap 3 Wang 22
ar 1 2 50
ar 1 3 60
at 1 101
att 2 1 101
att 3 1 101
arem 1 17 1 1 101
sm 1
qm 1
qm 2
qm 3
text
Apply
ap 1 Zhang 20
ap 2 Li 21
ap 3 Wang 22
ap 4 Zhao 23
ar 1 2 100
ar 2 3 90
ar 3 4 80
sei 101
sei 102
sei 103
aem 1 101 1 2 0
sm 1
aem 2 101 2 3 0
sm 2
aem 3 102 3 4 0
sm 3
qp 101
qp 102
qp 103
dce 2
qp 101
qp 102
qp 103
text
Apply
ap 1 Zhang 20
ap 2 Li 21
ap 3 Wang 22
ap 4 Zhao 23
ar 1 2 150
ar 1 3 100
ar 1 4 80
ar 2 3 120
qba 1
ar 1 2 50
qba 1
mr 1 3 100
qba 1
......
|
心得体会
经过本单元的学习,我体会到了规格在大模型辅助编码中的便利性和重要作用,同时对于一些编程实践思想有了新的认识,整个项目不是一道简单的题目,用精妙的方法实现某些特定的目的,而是可以通过更朴素使用的方法,如维护变量等,基于整个项目而不是一个方法来看待任务。同时对增删查改等操作编码时的操作实践有了更深的理解和体会。