Java HashMap.get返回多值异常:图反转方法错误排查
你遇到的这个问题核心原因是同一个ArrayList实例被绑定到了HashMap的多个不同键上,导致当你向其中一个键对应的列表添加元素时,其他共享该实例的键的列表也会同步变化。
看你的reverseGraph方法代码片段:
for(Integer x:g.getVertices()) { ArrayList<Integer> edges = new ArrayList<Integer>(); edges.add(x); // ... for(Integer y:g.getAdjList().get(x)) { // ... if(revAdjList.containsKey(y)) { revAdjList.get(y).add(x); } else { revAdjList.put(y, edges); // 这里就是问题所在! } } }
在每个外层循环(遍历x)中,你只创建了一个edges列表。当处理当前x对应的多个y时,如果这些y都不在revAdjList里,你会把同一个edges实例依次绑定到这些y键上。比如某个x对应的y=5和y=6都不存在于revAdjList,那么键5和键6都会指向同一个ArrayList对象。之后当你调用revAdjList.get(6).add(3)时,因为键5和6的列表是同一个实例,所以键5的列表也会多出一个3,这就是你日志里看到的异常现象。
只需要在else分支中,为每个新的y创建一个全新的ArrayList实例,而不是复用当前x循环里的edges列表。修改代码如下:
if(revAdjList.containsKey(y)) { revAdjList.get(y).add(x); } else { // 为每个y创建独立的ArrayList,避免实例共享 ArrayList<Integer> newEdges = new ArrayList<>(); newEdges.add(x); revAdjList.put(y, newEdges); // 如果你用Java 9及以上版本,也可以用简化写法: // revAdjList.put(y, new ArrayList<>(List.of(x))); }
调试代码清理:你代码里有一行硬编码的
revAdjList.get(5),这是调试时的残留,建议改成revAdjList.get(y),不然日志只会打印键5的内容,影响调试准确性。顶点列表优化:反转图的顶点集合和原图完全一致,不需要通过遍历邻接边来逐个添加
revVertices,直接复制原图的顶点列表即可:
ArrayList<Integer> revVertices = new ArrayList<>(g.getVertices());
这样可以避免漏掉原图中的孤立节点(那些没有出边的顶点)。
修改后,每个键对应的ArrayList都是独立的实例,向一个键的列表添加元素时,不会影响其他键的列表。你可以重新运行代码,观察日志,就能看到键5和键6的列表不再同步变化了。
内容的提问来源于stack exchange,提问作者Cosmin Şoavă

