我遇到问题(不再使用stackoverflow(hehe))尝试使用路径压缩实现UnionFind结构算法时查找算法。
我有标准的int数组,数组可以变大 - >它工作正常,直到60.000.000元素。
我的联盟功能如下:
public void unite(int p, int q) {
if(p >= 0 && p < id.length && q >= 0 && q < id.length){
if (isInSameSet(p, q)) return;
id[find(p)] = find(q);
stevilo--;
}
}
我的isInSameSet如下所示:
public boolean isInSameSet(int p, int q) {
if(p >= 0 && p < id.length && q >= 0 && q < id.length)
return find(p) == find(q);
return false;
}
我在Find中尝试了迭代方法:
public int find(int i) {
while (i != id[i]){
id[i] = id[id[i]];
i = id[i];
}
return i;
}
和尾巴退缩:
public int find(int i) {
int p = id[i];
if (i == p) {
return i;
}
return id[i] = find(p);
}
我的代码中有什么错过的吗?还有其他方法可以解决这类问题吗?
@edit:将构造函数添加到代码中:
public UnionFind(int N) {
stevilo = N;
id = new int[N];
for(int i = 0; i < N; i++){
id[i] = i;
}
@ edit2(更好的解释和新发现): 问题不在于stackoverflow,不到60.000.000元素,这足以解决我的问题。
我正在调用这样的测试联盟:
for(i=0;i<id.length-1;i++)
unite(i,i+1)
所以结尾对是这样的:
0:1, 1:2, 2:3, 3:4,..
仅作为测试的最佳选项的示例仅表示:)
然后我检查0的代表是否是表中的最后一个元素(99个表示100个元素)并且它是否有效。
问题是,我的算法只有在初始元素各自都在它们自己的并集中时才有效(0:0,1:1,2:2,3:3)。如果我已经设置了不同的联盟(0:2,1:6,2:1,3:5,......),我的测试算法将停止工作。
我已将其缩小到Find函数中的问题,可能与路径压缩有关
id[i] = id[id[i]].
答案 0 :(得分:2)
一个小优化就是摆脱isInSameSet ......
public void unite(int p, int q) {
if(p >= 0 && p < id.length && q >= 0 && q < id.length){
int rootp = find(p);
int rootq = find(q);
if (rootp==rootq) return;
id[rootp] = rootq;
stevilo--;
}
}
答案 1 :(得分:1)
Union-Find数据结构通常包括两种不同的优化。一个是路径压缩。你有。
但是其他优化发生在联盟中,在那里你仔细选择两个根中的哪一个来生成另一个的孩子,通常是通过Union-By-Rank或Union-By-Size。通过该优化,您的树永远不应该足够深,以获得堆栈溢出。但是,您的联合功能似乎缺少这种优化。
答案 2 :(得分:1)
我曾为UnionFind
编写了一个算法,其时间复杂度为O(log *(n))。那是n的迭代对数。该算法在继续连接节点以提高效率时压缩树的路径。我发现它非常有效,尽管我还没有针对巨大的阵列大小进行实际测试。这是代码:
public class UnionFind
{
private int[] id;
public UnionFind(int capacity)
{
id = new int[capacity];
for (int i = 0; i < capacity; i++)
{
id[i] = i;
}
}
public boolean isConnected(int p, int q)
{
return root(p) == root(q);
}
public void connect(int p, int q)
{
if (isConnected(p, q))
{
return;
}
id[root(p)] = root(q);
}
private int root(int p)
{
int temp = p;
if (p != id[p] && id[id[p]] != id[p])
{
while (p != id[p])
{
p = id[p];
}
id[temp] = id[p];
}
return id[p];
}
}