Java自定义Graph类中如何删除HashMap所存ArrayList内的Arch对象
问题原因
- 类型定义不兼容:你的Graph类中
arch成员的泛型定义为HashMap<N,ArrayList<T>>,但你实际存储的是Arch<N,T>类型的对象,T是Arch的标签类型,此处定义存在错误,运行时类型擦除会导致取值、删除逻辑异常。 - 遍历删除逻辑错误:Java增强for循环(for-each)底层基于迭代器实现,直接调用ArrayList的
remove方法会破坏迭代器的遍历规则,轻则出现游标偏移导致漏删、无修改效果,重则抛出ConcurrentModificationException异常。 - 判断条件逻辑错误:你要删除起点为start、终点为end的边,判断条件应该为
a.start.equals(start) && a.end.equals(end),你写的||逻辑不符合需求。同时如果N是自定义类型,不能用==比较对象内容,必须调用equals方法。 - 场景逻辑缺失:如果你的图是无向图(
oriented为false),还需要同步删除end节点对应列表中起点为end、终点为start的边,同时删除成功后需要更新nArch计数。
修复实现
首先修正Graph类的arch成员泛型定义:
private HashMap<N,ArrayList<Arch<N,T>>> arch;
修正后的deleteArch方法:
public void deleteArch(N start, N end) { // 空校验避免空指针异常 if (!arch.containsKey(start)) { return; } ArrayList<Arch<N,T>> archsForNode = arch.get(start); // 使用迭代器执行删除避免并发修改问题 Iterator<Arch<N,T>> iterator = archsForNode.iterator(); int deleteCount = 0; while (iterator.hasNext()) { Arch<N,T> a = iterator.next(); if (a.start.equals(start) && a.end.equals(end)) { iterator.remove(); deleteCount++; // 如果不需要保留重复边,此处可直接break提升性能 } } // 无向图需要同步删除反向边 if (!oriented && arch.containsKey(end)) { ArrayList<Arch<N,T>> reverseArchs = arch.get(end); Iterator<Arch<N,T>> reverseIt = reverseArchs.iterator(); while (reverseIt.hasNext()) { Arch<N,T> a = reverseIt.next(); if (a.start.equals(end) && a.end.equals(start)) { reverseIt.remove(); deleteCount++; } } } // 更新边的总计数 nArch -= deleteCount; }
注意事项
自定义节点类型N必须重写equals和hashCode方法,否则内容相同的对象会被识别为不同对象,导致匹配删除失败。
内容的提问来源于stack exchange,提问作者Sof
相关产品推荐
相关产品推荐

