HashSet.contains()使用问题排查:克鲁斯卡尔算法迷宫生成坐标检测
问题根源:Java数组的
equals()坑 Yep,你完全说对了——问题就出在HashSet.contains()的使用上!核心原因是Java里数组的equals()方法默认比的是对象引用,不是数组里的内容。
你代码里每次都新建一个int[]{x, y - 2},哪怕这个新数组的元素和集合里某个数组完全一样,它也是个全新的对象,内存地址不一样,所以contains()永远返回false。
几种可行的修复方案
1. 用List<Integer>替代int[]
List的equals()方法是专门比较集合内容的,把坐标换成List就能让contains()正常工作:
// 把cells的类型改成 HashSet<HashSet<List<Integer>>> for (HashSet<List<Integer>> h : cells) { if (h.contains(Arrays.asList(x, y - 2))) { set1 = h; } }
直接用Arrays.asList()把坐标转成List就行,或者提前把所有坐标都存成ArrayList<Integer>。
2. 自定义坐标类并重写equals()和hashCode()
创建一个简单的Point类来封装坐标,自己控制相等性判断逻辑,这也是最规范的做法:
import java.util.Objects; class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Point point = (Point) o; return x == point.x && y == point.y; } @Override public int hashCode() { return Objects.hash(x, y); } }
然后把集合里的元素都换成Point对象:
// cells的类型改为 HashSet<HashSet<Point>> for (HashSet<Point> h : cells) { if (h.contains(new Point(x, y - 2))) { set1 = h; } }
这种方式代码可读性更高,后续扩展也方便,比如要加坐标运算的话直接在Point类里加方法就行。
3. 手动遍历比较数组内容(不推荐)
如果不想改数据结构,也可以手动遍历集合里的每个数组,逐个元素比较:
for (HashSet<int[]> h : cells) { for (int[] coord : h) { if (coord[0] == x && coord[1] == y - 2) { set1 = h; break; } } }
但这种方式效率很低,尤其是当迷宫规模大的时候,不建议用。
额外小提示
对了,用Kruskal算法生成迷宫时,通常会用**并查集(Union-Find)**来管理连通分量,比嵌套HashSet的方式效率高太多了,还能避免这类对象相等性的问题。如果还没试过,强烈建议切换到并查集实现,会省心很多~
内容的提问来源于stack exchange,提问作者totallyrin
相关产品推荐
相关产品推荐

