面向对象设计与构造课程作业 _第三单元总结 _北京航空航天大学计算机学院 2019春季...
面向对象设计与构造课程作业
第三单元总结
北京航空航天大学计算机学院 2019春季
17373468 赵子敬
单元主题:规格的理解、撰写和使用(图和地铁运行系统)
第一次作业:实现两个容器类Path
和PathContainer
,JML
规格入门级的理解和代码实现。
第二次作业:实现容器类Path
和数据结构类Graph
,JML
规格进阶级的理解和代码实现、设计模式的简单实战,以及单元测试的初步使用尝试。
第三次作业:实现容器类Path
,地铁系统类RailwaySystem
,JML
规格进阶级的理解和代码实现、设计模式和单元测试的进阶级实战。
一、JML
语言的理论基础、应用工具链情况
(本段较多引用网络教程,链接:http://tech.it168.com/a2009/0222/266/000000266316.shtml)
面向对象分析和设计的原则之一就是应当尽可能地把过程设想往后推。我们大多数人只在实现方法之前遵守这一规则。一旦确定了类及其接口并该开始实现方法时,我们就转向了过程设想。那么到底有没有别的选择?和大多数语言一样,编写 Java 代码时,我们需要为计算每个方法的结果一步一步地提供过程。
就其本身而言,过程化表示法只是说 如何做某事,却不曾说过我们正在设法做 什么。在动手之前了解我们想要取得的结果,这可能会有用,但是 Java 语言没有提供显式地将这种信息合并到代码中的方法。
Java 建模语言(JML
)将注释添加到 Java 代码中,这样我们就可以确定方法所执行的内容,而不必说明它们如何做到这一点。有了JML
,我们就可以描述方法预期的功能,无需考虑实现。通过这种方法,JML
将延迟过程设想的面向对象原则扩展到了方法设计阶段。
JML
编译器可以生成类文件,这些文件可以在运行时自动检查 JML
规范。如果程序没有完成其 JML
注释中规定要做的事,则 JML
会抛出一个未经检查的异常,指出违反了哪部分规范。这在捕获错误或帮助使文档(JML
注释格式)与代码保持同步方面都非常有用。
JML
运行时断言检查编译器是数目不断增多的使用 JML
的工具中的第一个。其它工具包括 jmldoc
和 jmlunit
。 jmldoc
类似于 javadoc
,不过它还在生成的 HTML 文档中包含了 JML
规范。 jmlunit
生成测试案例类的框架,它使 JML
能方便地与 JUnit
结合使用。
二、【选做】部署 SMTSolver
,至少选择3个主要方法来尝试进行验证,报告结果
三、部署 JMLUnitNG
/JMLUnit
,针对 Graph
接口的实现自动生成测试用例, 并结合规格对生成的测试用例和数据进行简要分析
本次作业我没有使用 JMLUnit
进行测试,只是使用了 JUnit
,针对规格实现了单元测试,在此简单梳理随机用例测试代码。
private static final int maxPathSize = 80; private static final int maxDistinctNode = 120; private RailwaySystem system = new MyRailwaySystem(); private ArrayList<Integer> nodeSet = new ArrayList<>(); private ArrayList<Path> pathSet = new ArrayList<>();
上面这段定义测试类全局变量,maxPathSize
和 maxDistinctNode
两个常量用来便于修改测试过程中数据范围边界;system
实例化一个 RailwaySystem
类,作为测试的对象; nodeSet
和 pathSet
分别用来存储测试类生成的路径和节点。
private Path generateRadomPath() { int pathSize = (int)(2 + Math.random() * (maxPathSize - 1)); ArrayList<Integer> pathNodeList = new ArrayList<>(); for (int i = 0; i < pathSize; i++) { int flag = (int)(Math.random() * 2); if ((nodeSet.size() == maxDistinctNode || flag == 0) && nodeSet.size() != 0) { int index = (int)(Math.random() * nodeSet.size()); Integer node = nodeSet.get(index); pathNodeList.add(node); } else { Integer newNode = (int)(Integer.MIN_VALUE + Math.random() * ((long)Integer.MAX_VALUE - (long)Integer.MIN_VALUE + 1)); pathNodeList.add(newNode); nodeSet.add(newNode); } } int[] pathList = new int[pathNodeList.size()]; for (int i = 0; i < pathNodeList.size(); i++) { pathList[i] = pathNodeList.get(i); } System.out.println("adding path, path size: " + pathSize); System.out.println(pathNodeList); return new MyPath(pathList); }
上面这段为随机生成路径。首先路径长度是在最大范围内随机的,其次循环生成在int范围内随机的节点。为了保证整个系统中的节点数不超过限制,在生成路径时即存储所有节点,若超过限制则在已有的节点里寻找节点构建新路径。最后打印生成路径信息。
private Path removeRandomPath() { int pathIndex = (int)(Math.random() * pathSet.size()); Path toBeRemoved = pathSet.get(pathIndex); System.out.println("the following path has been removed."); System.out.println(toBeRemoved); pathSet.remove(pathIndex); nodeSet.clear(); int i; int j; for (i = 0; i < pathSet.size(); i++) { for (Integer node : pathSet.get(i)) { if (!nodeSet.contains(node)) { nodeSet.add(node); } } } return toBeRemoved; }
上面这段为随机删除路径。在已有的路径随机选择一个下标将对应的路径删除,随即更新节点集信息。
@Before public void setUp() throws Exception { int addNum = (int)(1 + Math.random() * 50); for (int i = 0; i < addNum; i++) { Path newPath = generateRadomPath(); pathSet.add(newPath); system.addPath(newPath); } int removeNum = (int)(Math.random() * addNum); for (int i = 0; i < removeNum; i++) { Path toBeRemoved = removeRandomPath(); system.removePath(toBeRemoved); } System.out.println("system has been built."); System.out.println("total paths: " + pathSet.size()); System.out.println("distinct node count: " + nodeSet.size()); }
上面这段是 JUnit
框架的 @Before
模块,在单元测试之前初始化测试类。在此仍然采用随机的方式,在增删指令数限定范围内随机增加路径,随后在不超过已有路径数量的范围内随机删除路径,最终打印现有地铁系统路径数量和节点数量信息,在测试之前建立好地铁系统。
@Test public void containsNode() { int index = (int)(Math.random() * nodeSet.size()); assert system.containsNode(nodeSet.get(index)); System.out.println("correct: " + nodeSet.get(index) + " is in the system."); int node = (int)(Math.random() * Integer.MAX_VALUE); while (nodeSet.contains(node)) { node = (int)(Math.random() * Integer.MAX_VALUE); } assert system.containsNode(nodeSet.get(index)); System.out.println("correct: " + node + " is not in the system."); }
上面这段是 JUnit
单元测试针对 containsNode
接口的测试。此处由于我们已经在测试类存储了所有节点,因此只是从测试类取出了已有节点或随机生成新节点,无需按照规格遍历所有路径即可找到测试节点。上面这段代码从正反分别验证,在系统中的节点和不在系统中的节点均有测试。
@Test public void containsEdge() { int index = (int)(Math.random() * pathSet.size()); Path testPath = pathSet.get(index); index = (int)(Math.random() * (testPath.size() - 1)); int fromNode = testPath.getNode(index); int toNode = testPath.getNode(index + 1); assert system.containsEdge(fromNode, toNode); System.out.println("correct: edge (" + fromNode + ", " + toNode + ") is in the system"); index = (int)(Math.random() * nodeSet.size()); fromNode = nodeSet.get(index); index = (int)(Math.random() * nodeSet.size()); toNode = nodeSet.get(index); boolean flag = true; while (flag) { flag = false; for (Path path : pathSet) { for (int i = 0; i < path.size() - 1; i++) { if ((path.getNode(i) == fromNode && path.getNode(i + 1) == toNode) || (path.getNode(i) == toNode && path.getNode(i + 1) == fromNode) || fromNode == toNode) { flag = true; break; } } if (flag) { break; } } if (flag) { index = (int)(Math.random() * nodeSet.size()); toNode = nodeSet.get(index); } } assert !system.containsEdge(fromNode, toNode); System.out.println("correct: edge (" + fromNode + ", " + toNode + ") is not in the system"); }
上面这段是 JUnit
单元测试针对 containsEdge
接口的测试。这段测试严格遵循了规格,按照规格的定义对边进行了测试,同样是从正反两方面验证,首先在已有路径随机选择一条路,再从中随机选择一条边取出进行测试,确保这条边是属于系统的;而另一方面寻找不属于系统的边则比较麻烦,需要首先随机寻找节点,再遍历系统确保所有路径都不包含这条边。
还有更多接口的单元测试,代码过于冗长在此不再赘述。以 containsEdge
为例,测试的输出信息如下:
...junit4 MyRailwaySystemTest,containsEdgeadding path, path size: 22[1232241898, 1232241898, 378328260, 1232241898, 1232241898, 378328260, 1059498109, 1059498109, 1059498109, 1232241898, 513409004, -1001154432, -1001154432, -1001154432, 1059498109, -1151735537, 1478286012, -2011719206, -1151735537, -338002509, -1719290353, -1077194302]adding path, path size: 8[-1009325207, -1009325207, 280639520, 378328260, 1640517423, -1009325207, -358986601, 1059498109]adding path, path size: 42[966545447, 378328260, 1215082132, -1922842082, -1922842082, -1009325207, 378328260, -1151735537, -1009325207, -358986601, -1061266839, -1719290353, 410078478, 2085504756, 1232241898, 280639520, -2060925210, -369734078, 1223397009, -426274874, 1223397009, 933549319, -761667280, -271824825, 467283959, -1365251337, 1032049891, -1009325207, 1190892105, -1151735537, 1478286012, 1232241898, -1077194302, 1288726621, 1313963050, -1612728892, -73540680, -1719290353, 1640517423, -1873436263, -426274874, -426274874]adding path, path size: 54[1690346573, 402468808, -1873436263, -1873436263, 1232241898, -1061266839, 1640517423, 1475715686, 1977518312, 1575320703, -413736847, -1505480721, 1288726621, -1723345819, -73540680, 723556111, 1886070244, 467283959, 2015089536, -1719290353, -1061266839, 1478286012, 1762562422, -1719290353, -1001154432, 2015089536, 11719880, 1919254022, -1922842082, -87287690, -1503898901, -1489990093, 1882643122, 1288726621, 1139289371, 2015089536, -1365251337, 2101859962, -269155122, -966483414, 1575320703, 723556111, 410078478, -910520886, -271824825, -1422471783, 1575320703, -1422471783, 1139289371, 257175990, -1503898901, 2052736417, 1690346573, -1723345819]adding path, path size: 58[-583849437, 1190892105, -1196197506, -910520886, -1756866206, 273438400, -1814841704, 725680019, -73540680, -506344367, -73540680, -1365251337, -309934114, 465396124, 1223397009, -860023481, -369734078, 1204976612, 1762562422, -25286283, 467283959, 1886070244, 1736431410, -1968909372, 1478286012, 2052736417, 755188845, -2060925210, 1690922899, -1756866206, 1762562422, 816076988, -910520886, 723556111, 151760211, -2011719206, -1505480721, 1357764646, -301487943, 2085504756, -354252823, 1554967211, -1008226810, 933549319, 1221881081, 1191566630, -87287690, 755188845, -641269296, -1513703690, -830510707, -90020217, 437843332, -271824825, -768990883, 228240350, -1505480721, 1223397009]adding path, path size: 9[-70177856, 1278044153, -269155122, 816076988, -1263627592, 180011778, 11719880, -271824825, -34994370]adding path, path size: 28[1762562422, -420234991, 755188845, 1167139935, -377147417, 549200588, 281646107, 1118305039, -1429609969, -1632813850, -1873436263, -562522988, -1922842082, -510676862, -761667280, 1357764646, -1151735537, 876397354, 419176848, 941885397, 1518270263, -309934114, 1091165502, 1221881081, 1993619079, 1810909193, -625828750, 1052359578]adding path, path size: 55[1690346573, -73540680, -1758621909, 1575320703, 1052359578, -301487943, -1873436263, 2015089536, 1223397009, 1478286012, -1723345819, 1167139935, 1191566630, -641269296, -1009325207, 816076988, 1118305039, 1091165502, 1690346573, -1489990093, -269155122, -1077194302, 1690346573, 11719880, -73540680, -966483414, -506344367, -1756866206, 1640517423, 281646107, 1059498109, -1873436263, -70177856, 437843332, 1288726621, -1196197506, 1810909193, 437843332, 1191566630, -1612728892, -761667280, 2101859962, -1489990093, -1968909372, 419176848, 1288726621, 1052359578, 281646107, -1719290353, -1196197506, -562522988, -1756866206, 228240350, -1263627592, 1882643122]adding path, path size: 35[1221881081, -506344367, -338002509, -1503898901, -761667280, -1489990093, 410078478, 1690922899, -1719290353, 180011778, 1919254022, 513409004, 1052359578, -860023481, -910520886, 1091165502, 402468808, -271824825, 257175990, -358986601, 1478286012, 876397354, 1215082132, -1151735537, -377147417, 1139289371, -625828750, 410078478, -301487943, 755188845, -562522988, -25286283, 437843332, 2052736417, -1719290353]adding path, path size: 19[-1719290353, 1518270263, 1993619079, -358986601, 257175990, -583849437, 257175990, 378328260, 1882643122, 1810909193, 281646107, -358986601, 1575320703, -1814841704, 151760211, 11719880, -269155122, -338002509, -761667280]adding path, path size: 48[1215082132, 467283959, 1690922899, 1215082132, 933549319, 280639520, -354252823, 1554967211, 1690346573, 273438400, -25286283, 1223397009, 941885397, 1059498109, 280639520, -761667280, -426274874, 378328260, -1719290353, -413736847, 1554967211, -1968909372, -1365251337, 1993619079, -966483414, -1196197506, -1503898901, 273438400, 1690922899, 1313963050, 1288726621, -1196197506, -338002509, 1139289371, -1758621909, 1091165502, 1690346573, -1632813850, -269155122, 1690922899, 1278044153, -301487943, -301487943, -641269296, -641269296, -426274874, 410078478, 2052736417]adding path, path size: 76[-1489990093, -269155122, 1313963050, 281646107, 1204976612, 1139289371, 281646107, -1077194302, 437843332, -73540680, 1221881081, -269155122, -830510707, 941885397, 1475715686, 1518270263, -338002509, 1032049891, 1190892105, 1139289371, 1278044153, 1640517423, -1365251337, -1489990093, 402468808, -358986601, 1575320703, 1204976612, 1993619079, 966545447, 11719880, -1196197506, -1429609969, 941885397, -1365251337, 1690346573, 1191566630, 1554967211, 933549319, 1313963050, -1429609969, -1719290353, 1223397009, -1814841704, -87287690, 1640517423, -1009325207, -1632813850, -2011719206, 1475715686, -73540680, -1922842082, -506344367, -309934114, -562522988, -1365251337, 1191566630, 755188845, -966483414, -1968909372, 257175990, -910520886, 1221881081, 723556111, 933549319, 419176848, -1365251337, -583849437, -70177856, 281646107, -910520886, -1503898901, -1723345819, -1489990093, 1762562422, 280639520]adding path, path size: 27[-768990883, 549200588, 1762562422, -271824825, 1032049891, -1196197506, -562522988, 1575320703, -1263627592, -1001154432, -73540680, -1873436263, -301487943, -1922842082, -1612728892, 1221881081, 273438400, 1232241898, -354252823, -2011719206, 437843332, 1357764646, -420234991, 1736431410, -1422471783, 1575320703, -506344367]adding path, path size: 72[1977518312, -87287690, -1503898901, 1052359578, -420234991, 933549319, -1632813850, -1009325207, 151760211, 966545447, 2085504756, -1758621909, 1575320703, 1190892105, -1263627592, -369734078, -1513703690, -301487943, 755188845, -271824825, -1503898901, 1288726621, 1882643122, -420234991, -34994370, 1690922899, -625828750, -761667280, 1554967211, 933549319, 1091165502, 273438400, 1518270263, -354252823, 1478286012, 1762562422, -1196197506, -1263627592, 378328260, -1503898901, 410078478, 1810909193, 1690346573, 513409004, -562522988, -1077194302, 410078478, -1873436263, 1091165502, 1091165502, -301487943, 228240350, -413736847, -1008226810, -1422471783, -1632813850, -338002509, -1489990093, -369734078, -1968909372, 1518270263, -830510707, 1288726621, -1422471783, 2101859962, 1215082132, 1357764646, 1977518312, 1288726621, 933549319, -562522988, -506344367]the following path has been removed.[1215082132, 467283959, 1690922899, 1215082132, 933549319, 280639520, -354252823, 1554967211, 1690346573, 273438400, -25286283, 1223397009, 941885397, 1059498109, 280639520, -761667280, -426274874, 378328260, -1719290353, -413736847, 1554967211, -1968909372, -1365251337, 1993619079, -966483414, -1196197506, -1503898901, 273438400, 1690922899, 1313963050, 1288726621, -1196197506, -338002509, 1139289371, -1758621909, 1091165502, 1690346573, -1632813850, -269155122, 1690922899, 1278044153, -301487943, -301487943, -641269296, -641269296, -426274874, 410078478, 2052736417]the following path has been removed.[1690346573, -73540680, -1758621909, 1575320703, 1052359578, -301487943, -1873436263, 2015089536, 1223397009, 1478286012, -1723345819, 1167139935, 1191566630, -641269296, -1009325207, 816076988, 1118305039, 1091165502, 1690346573, -1489990093, -269155122, -1077194302, 1690346573, 11719880, -73540680, -966483414, -506344367, -1756866206, 1640517423, 281646107, 1059498109, -1873436263, -70177856, 437843332, 1288726621, -1196197506, 1810909193, 437843332, 1191566630, -1612728892, -761667280, 2101859962, -1489990093, -1968909372, 419176848, 1288726621, 1052359578, 281646107, -1719290353, -1196197506, -562522988, -1756866206, 228240350, -1263627592, 1882643122]the following path has been removed.[1690346573, 402468808, -1873436263, -1873436263, 1232241898, -1061266839, 1640517423, 1475715686, 1977518312, 1575320703, -413736847, -1505480721, 1288726621, -1723345819, -73540680, 723556111, 1886070244, 467283959, 2015089536, -1719290353, -1061266839, 1478286012, 1762562422, -1719290353, -1001154432, 2015089536, 11719880, 1919254022, -1922842082, -87287690, -1503898901, -1489990093, 1882643122, 1288726621, 1139289371, 2015089536, -1365251337, 2101859962, -269155122, -966483414, 1575320703, 723556111, 410078478, -910520886, -271824825, -1422471783, 1575320703, -1422471783, 1139289371, 257175990, -1503898901, 2052736417, 1690346573, -1723345819]the following path has been removed.[-70177856, 1278044153, -269155122, 816076988, -1263627592, 180011778, 11719880, -271824825, -34994370]the following path has been removed.[966545447, 378328260, 1215082132, -1922842082, -1922842082, -1009325207, 378328260, -1151735537, -1009325207, -358986601, -1061266839, -1719290353, 410078478, 2085504756, 1232241898, 280639520, -2060925210, -369734078, 1223397009, -426274874, 1223397009, 933549319, -761667280, -271824825, 467283959, -1365251337, 1032049891, -1009325207, 1190892105, -1151735537, 1478286012, 1232241898, -1077194302, 1288726621, 1313963050, -1612728892, -73540680, -1719290353, 1640517423, -1873436263, -426274874, -426274874]the following path has been removed.[-583849437, 1190892105, -1196197506, -910520886, -1756866206, 273438400, -1814841704, 725680019, -73540680, -506344367, -73540680, -1365251337, -309934114, 465396124, 1223397009, -860023481, -369734078, 1204976612, 1762562422, -25286283, 467283959, 1886070244, 1736431410, -1968909372, 1478286012, 2052736417, 755188845, -2060925210, 1690922899, -1756866206, 1762562422, 816076988, -910520886, 723556111, 151760211, -2011719206, -1505480721, 1357764646, -301487943, 2085504756, -354252823, 1554967211, -1008226810, 933549319, 1221881081, 1191566630, -87287690, 755188845, -641269296, -1513703690, -830510707, -90020217, 437843332, -271824825, -768990883, 228240350, -1505480721, 1223397009]system has been built.total paths: 8distinct node count: 107correct: edge (-1922842082, -510676862) is in the systemcorrect: edge (1690922899, 1736431410) is not in the systemProcess finished with exit code 0
生成的测试数据是完全随机的,这个特性有优势也有劣势。优势在于可以全面地并且随即地测试接口实现,并可以灵活调整测试规模,方便地进行多次不同数据测试。当然,明显的劣势在于随即数据难以很好地兼顾边界和特殊情况,只能通过大量多次测试来提升语句覆盖率,而很难达到语句覆盖100%。
四、按照作业梳理自己的架构设计,并特别分析迭代中对架构的重构
第一次作业:
第一次作业要求比较简单,只需要实现路径( path
)的构造和路径容器( pathContainer
)的构造。pathContainer
需要实现路径的增添、删除、编号,以及一个相对特殊的方法:统计节点数。由于是第一次作业,原本的思路就是按照规格中规中矩地实现了,但是在性能要求的影响下我们发现不可以按照规格一模一样地实现代码,因为采用静态的容器不能满足增删需求,用动态数组统一进行每一个方法的计算查询又会耗费大量时间,这也是我们第一次体会到,规格仅仅用来规范输入输出,而具体的实现是自由的。只要保证与规格的输入输出要求一致,应该尽可能构思性能更好的实现方法。
因此在两个接口实现的过程中,为了提升时间性能我都适当牺牲了空间性能。在 Path
接口的实现过程中我才用了这样的存储:
private ArrayList<Integer> nodeList = new ArrayList<>(); private HashSet<Integer> nodeSet = new HashSet<>(); public MyPath(int... nodeList) { for (int node : nodeList) { this.nodeList.add(node); this.nodeSet.add(node); } }
同时使用动态数组和集合,把每一个节点存两遍,这样既保留路径原有节点和顺序信息,也能够方便地查询节点和统计不相同节点数。
在 pathContainer
接口实现中我同样采取了存储多次的方法,将不同类型信息多次存储,已达到快速查询的目的:
private HashMap<Integer, Path> pathMap1 = new HashMap<>();private HashMap<Path, Integer> pathMap2 = new HashMap<>();private static int idCount = 0;private ArrayList<Integer> nodeList = new ArrayList<>();private HashSet<Integer> distinctNodeSet = new HashSet<>();public MyPathContainer() {}
其中 pathMap1
和 pathMap2
将路径和其编号一一对应地存储,为了使查询更快使用哈希表,而为了能实现路径-编号双向查询我使用了两个哈希表,并为路径重写了 hashCode
和 equals
方法。而为了查询不相同节点,我将所有路径的节点再次存储,这样一来所有查询的复杂度都被降到常数。
第二次作业:
第二次作业的需求比第一次多了一些,主要挑战在于要求查询节点的连通性以及计算最短路径。这两个新增需求看似可以通过少量对第一次代码的扩展来实现,但实际上如果这样做,时间性能将不能够支撑代码通过测试。但看计算最短路径,不论是迪杰斯特拉还是弗洛伊德,时间复杂度都在三次方量级。按照作业需求,高达数千次的查询操作会耗费大量时间。并且如果在动态容器基础上操作,不论是查询计算还是增删,都会有很多Java包调用的开销。因此我采用了多重存储+静态二维数组的方式,并单独封装一类维护图结构。
private static final int SIZE = 400;private HashMap<Integer, Integer> idexMap = new HashMap<>();private HashMap<Integer, Integer> nodeMap = new HashMap<>();private int[][] adjMatrix = new int[SIZE][SIZE];private int[][] dstMatrix = new int[SIZE][SIZE];
这是我单独封装的 Matrix
类全局变量,我使用了静态的二维数组作为增删和查询路径操作的主要对象,而为了让动态变化的节点可以反映在静态的二维数组上,我才用了两个哈希表将节点映射为数组下标,并实现双向索引。而二维数组我也采用了两重存储,dstMatrix
用来存储计算好的两点之间最短距离,而 adjMatrix
则用来存储点的邻接情况。这样一来,只需要在每次增删操作时改变矩阵和映射关系,重新计算更新所有矩阵的信息,将繁杂的计算工作分摊给需求较少的增删操作,而每次的查询无非是访问了一个静态二维数组。
private void setDstMatrix() {int i;int j;int k;for (i = 0; i < SIZE; i++) {for (j = 0; j < SIZE; j++) {if (i == j) {dstMatrix[i][j] = 0;} else if (adjMatrix[i][j] > 0) {dstMatrix[i][j] = 1;} else {dstMatrix[i][j] = -1;}}}for (k = 0; k < SIZE; k++) {for (i = 0; i < SIZE; i++) {for (j = 0; j < SIZE; j++) {int temp = -1;if (dstMatrix[i][k] >= 0 && dstMatrix[k][j] >= 0) {temp = dstMatrix[i][k] + dstMatrix[k][j];}if (temp >= 0 &&(temp < dstMatrix[i][j] || dstMatrix[i][j] < 0)) {dstMatrix[i][j] = temp;}}}}}
上面这段代码是采用弗洛伊德算法更新距离矩阵。我们基于邻接矩阵来更新距离矩阵,初始化过程为,相同节点间距离为0,若两节点邻接则距离为1,其余节点间距离均为无穷(在这里使用了-1)。而弗洛伊德算法,遍历每个节点(变量k表示),对于每个节点,遍历整张图的其他所有节点对(变量i和j表示),查看如果k节点作为中间节点,i和j之间的路径如果通过k到达会不会更短,如果更短则更新i和j之间的距离。弗洛伊德算法的时间复杂度是n^3,理论上比迪杰斯特拉算法要慢,但是在本次作业中实测优于迪杰斯特拉,这可能是由于节点数目多但图较为稀疏的情况下迪杰斯特拉算法时间复杂度的常数项很大,而弗洛伊德能够始终保持稳定的三次方。
第三次作业:
第三次作业的需求比第二次再升一级,需要实现地铁线路中很现实的:最低票价查询、最少换乘查询和最少不满意度查询,以及相对独立的连通块个数查询。题目给出的模型我认为非常符合实际,地铁系统给出两站之间最少换乘是很有必要的功能;票价的模型是两站间距离加上最少换乘数的二倍,这与北京地铁实际票价计价方式一致;不满意度也很符合人们的实际心理,不满意度和路途远近、线路途径站点的平均人流量和换成次数有关,以我个人的经验,从沙河到学院路,在早晚高峰我宁愿选择站数更多的八号线,也不愿意选择在魔鬼西二旗换乘的十三号线。
仔细分析过后我们会发现,前三种查询都涉及到了换乘站的记录,这是我们前两次作业始料未及的。我们在第二次作业计算最短路的时候,不论是弗洛伊德算法还是迪杰斯特拉算法,都无法确定中途哪一站在换乘。而这次三个查询都需要确定,我们所选的这条路有哪些站在换乘。
而这个棘手的问题被王嘉仪同学提出的算法完美解决,即升级邻接矩阵。如果将每条路径也看成图,每条路径内部的联通情况和距离情况将被提前计算好,而原有 Matrix
类的邻接矩阵将被升级为每个单独路径的图的简单叠加。这样一来,不同路径之间的连通性就不会被直接显示在邻接矩阵中。接下来,在计算和换乘有关的最短路时,只需要按照需求分别存储其他的矩阵,基于升级后的邻接矩阵增加边权值即可。
例如在计算最低票价时,对每条Path, 任意两个直接连边,边权修改为距离+2,即在边权中直接加入换乘的钱,然后进行弗洛伊德算法的计算。这样做求出的结果多最后一次换乘的2,减去即可。这个做法能够保证正确性。因为任意一条求出的路径长度都是真实的路径长度+2,和中间的换乘次数无关。且不存在求出的最短路在一条路线上多次换乘的问题,因为每条路径上的任意两点都直接连有边。最少换乘问题,可以将每条边的边权设为1+很大的一个数(大于最多换乘次数,这个数被我设置为700),这样根据最短路的特性,求出最短路后/120即为换乘的次数。最少不满意度可以参考最低票价解决。
private static final int SIZE = 130;private static final int INF = Integer.MAX_VALUE;private static final int MODE = 700;private HashMap<Integer, Integer> idexMap = new HashMap<>();private HashMap<Integer, Integer> nodeMap = new HashMap<>();private HashSet<Path> pathSet = new HashSet<>();private int[][] adjMatrix = new int[SIZE][SIZE];private int[][] dstMatrix = new int[SIZE][SIZE];private int[][] cntMatrix = new int[SIZE][SIZE];private int[][] priMatrix = new int[SIZE][SIZE];private int[][] excMatrix = new int[SIZE][SIZE];private int[][] upvMatrix = new int[SIZE][SIZE];private int[] pre = new int[SIZE];private int cntCount;
以上代码即第三次作业多存储的诸多矩阵。同样,为了查找方便,我们适当地采用空间换时间。
private void setAdjMatrix(Integer lastNode, Integer curnNode) {int last = nodeMap.get(lastNode);int curn = nodeMap.get(curnNode);adjMatrix[last][curn] += 1;adjMatrix[curn][last] += 1; }private void setCntMatrix() {int i;int j;for (i = 0; i < SIZE; i++) {for (j = 0; j < SIZE; j++) {if (i == j) {cntMatrix[i][j] = upvMatrix[i][j] = 0;} else {cntMatrix[i][j] = upvMatrix[i][j] = INF;}}}for (Path path : pathSet) {for (Integer inode : path) {for (Integer jnode : path) {i = nodeMap.get(inode);j = nodeMap.get(jnode);int temp = ((MyPath)path).getUpv(inode, jnode) + 32;if (((MyPath)path).getLength(inode, jnode)< cntMatrix[i][j]) {cntMatrix[i][j] =((MyPath)path).getLength(inode, jnode);}if (temp < upvMatrix[i][j]) {upvMatrix[i][j] = temp;}}}} }private void setMatrixes() {int i;int j;int k;for (i = 0; i < SIZE; i++) {for (j = 0; j < SIZE; j++) {if (adjMatrix[i][j] > 0) {dstMatrix[i][j] = 1;} else {dstMatrix[i][j] = INF;}if (cntMatrix[i][j] != INF) {priMatrix[i][j] = cntMatrix[i][j] + 2;excMatrix[i][j] = 1 + MODE;} else {priMatrix[i][j] = INF;excMatrix[i][j] = INF;}if (i == j) {dstMatrix[i][j] = 0;priMatrix[i][j] = 0;excMatrix[i][j] = 0;}}}for (k = 0; k < SIZE; k++) {for (i = 0; i < SIZE; i++) {for (j = 0; j < SIZE; j++) {int temp1 = INF;int temp2 = INF;int temp3 = INF;int temp4 = INF;if (dstMatrix[i][k] != INF && dstMatrix[k][j] != INF) {temp1 = dstMatrix[i][k] + dstMatrix[k][j];}if (priMatrix[i][k] != INF && priMatrix[k][j] != INF) {temp2 = priMatrix[i][k] + priMatrix[k][j];}if (excMatrix[i][k] != INF && excMatrix[k][j] != INF) {temp3 = excMatrix[i][k] + excMatrix[k][j];}if (upvMatrix[i][k] < INF && upvMatrix[k][j] < INF) {temp4 = upvMatrix[i][k] + upvMatrix[k][j];}if (temp1 < dstMatrix[i][j]) {dstMatrix[i][j] = temp1;}if (temp2 < priMatrix[i][j]) {priMatrix[i][j] = temp2;}if (temp3 < excMatrix[i][j]) {excMatrix[i][j] = temp3;}if (temp4 <= upvMatrix[i][j]) {upvMatrix[i][j] = temp4;}}}} }public void addPath(Path path) {pathSet.add(path);Integer lastNode = null;Integer curnNode = null;for (Integer node : path) {curnNode = node;mapId(curnNode);if (lastNode != null && curnNode != null) {setAdjMatrix(lastNode, curnNode);}lastNode = node;}setCntMatrix();setMatrixes();setCntCount(); }
以上代码即增添路径的过程中对所存储矩阵的操作。
最终是连通快数目的计算,这一部分采用并查集的算法,不再赘述。
三次作业中,重构的方式无非是增添存储来适应更多的需求。不增添存储也是可以的,只是为了满足时间性能需求,我们不能够直接采用规格直接规定的算法,而是要思考更好的实现方式。
五、按照作业分析代码实现的bug和修复情况
说来惭愧,三次作业我一共只有一个愚蠢的bug,而这个bug导致我前两次作业强测都炸到六十多分,它就是:
@Overridepublic int compareTo(Path path) {int len1 = this.size();int len2 = path.size();int lin = Math.min(len1, len2);for (int k = 0; k < lin; k++) {Integer i1 = this.getNode(k);int i2 = path.getNode(k);if (!i1.equals(i2)) {return i1 - i2;}}return len1 - len2;}
没错,就是int类型的减法溢出。第一次作业我没有考虑到这一点,修复bug之后第二次作业重用第一次的代码竟然又忘记改这个地方,所以死两次。
这个故事告诉我们,千里之堤溃于蚁穴。
六、阐述对规格撰写和理解上的心得体会
说来惭愧,在这么多次训练过后,我所收获的有关规格的理解仅仅停留在写规格。当然,我理解为什么要产生规格,为什么要产生Java建模语言,为什么要进行基于规格的单元测试,这显然是这个单元给我的一大收获,我慢慢理解在大型工程开发中团队分工实现代码的过程。在企业研讨课上专家也向我们讲述了,架构设计不是一个过程,而是一个模块,不是设计完成后交付实现就完事了,而是作为一个模块随时调用随时调整的。
另一方面,这单元作业也让我真正实操了诸如继承、重写、接口实现和 JUnit
单元测试等多项以前模糊的概念。我认为这个单元代码量虽然不大,确是对我个人编码和理解能力很好的提升。
转载于:https://www.cnblogs.com/zhaozijing1998/p/10907950.html
面向对象设计与构造课程作业 _第三单元总结 _北京航空航天大学计算机学院 2019春季...相关推荐
- 【面向对象设计与构造】第一次博客作业
[面向对象设计与构造]第一次博客作业 一.程序结构分析 1. 第一次作业 类图 由于第一次作业难度较低,实现起来也不需要很复杂的算法,因此在编写程序的时候只建立了两个类,Main类主要负责多项式的读入 ...
- 面向对象设计与构造:oo课程总结
面向对象设计与构造:OO课程总结 第一部分:UML单元架构设计 第一次作业 UML图 MyUmlInteraction类实现接口方法,ClassUnit和InterfaceUnit管理UML图中的类和 ...
- 哈工大软件构造课程知识点总结(三)
系列文章目录 哈工大软件构造课程知识点总结(一) 哈工大软件构造课程知识点总结(二) 哈工大软件构造课程知识点总结(三) 哈工大软件构造课程知识点总结(四) 哈工大软件构造课程知识点总结(五) 哈工大 ...
- 研究生语音识别课程作业记录(三) 非特定人孤立词识别
研究生语音识别课程作业记录(三) 非特定人孤立词识别 前言 一. 任务要求 二. 识别方法 三. 语音数据库 四. 特征参数提取 五. 识别过程及分析 六. 实验总结 七. 小结 前言 研究生期间的语 ...
- 最全中国科学技术大学计算机学院课程资源!
前不久,我们在 GitHub 上发现了一个非常棒的项目--中国科学技术大学计算机学院课程资源,该项目目前已经收集了计算机与信息类.人文社科类.数学类.物理类.经管类等课程.包括电子版教材.参考书.讲义 ...
- 申请上计算机课的申请,诺丁汉大学计算机学院课程申请通道将即将关闭,抓紧上车了...
原标题:诺丁汉大学计算机学院课程申请通道将即将关闭,抓紧上车了 2021年9月入学的计算机学院研究生课程申请通道近日即将关闭! 温馨提示:由于计算机科学学院的研究生课程申请量很大,该学院的部分或全部研 ...
- 面向对象设计与构造第一次总结作业
第一次作业--多项式计算 ---结构分析 第一次作业我只使用了两个类,正像下面的类图所表示的那样,分别是Poly和ComputePoly.Poly类是不可变的,能保存一个多项式,可以进行加.减运算.C ...
- Java水果商店课程设计展望,JavaWeb课程作业之网上水果商店.zip
[实例简介] JavaWeb课程作业之网上水果商店(基本版),含sql文件,使用Eclipse+MySql制作,前端使用jquery,Ajax,JS DOM动态修改网页,后端采用jspModel,连接 ...
- java契约式编程_第三单元总结——JML契约式编程
OO第三单元博客作业--JML与契约式编程 OO第三单元的三次作业都是在课程组的JML规格下完成.完成作业的过程是契约式编程的过程:设计者完成规格设计,实现者按照规格具体实现.作业正确性的检查同样围绕 ...
- 北方工业大学计算机学院院长,王景中(北方工业大学院长)_百度百科
王景中 (北方工业大学院长) 语音 编辑 锁定 讨论 上传视频 王景中,信号与信息处理责任教授,数字图象处理研究室主任. 中文名 王景中 国 籍 出生日期 1962年 毕业院校 内蒙古大学代表作 ...
最新文章
- Flex Socket 安全沙箱问题解决
- Winform控件拖动
- oracle biee
- 点击跳转到QQ聊天界面
- redis——HyperLogLog
- Kubernetes 诞生七年,凭什么成为主流?
- MySQL 优化 —— ORDER BY 优化
- 使用 jQuery Mobile 与 HTML5 开发 Web App (三) —— jQuery Mobile 按钮
- 阿里笔试题解(2020.4.17场)
- 华为P40怎么解账号锁P40Pro忘记密码ID账号锁解除方案开机设备解锁帐号软件使用方法
- Fingerprint指纹识别学习
- 秘猿科技开源 CITA-Monitor
- 使用jQuery的click事件没反应
- 机器学习自然语言处理之英文NLTK(代码+原理)
- 【ELK】7. elasticsearch linux上操作es命令详解
- dayjs,当年月周日
- 艾赛克科技《RFID智能仓库管理系统》
- dd大牛的背包九讲-背包问题汇总
- C语言停车场管理系统,使用栈和队列实现
- 简单练习---学生课程信息