[英]Dealing with Union-Find algorithms with a lot of objects
我有一個問題(不再使用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]].
一個小的優化就是擺脫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--;
}
}
Union-Find數據結構通常包括兩種不同的優化。 一個是路徑壓縮。 你有。
但是其他優化發生在聯盟中,在那里你仔細選擇兩個根中的哪一個來生成另一個的孩子,通常是通過Union-By-Rank或Union-By-Size。 通過該優化,您的樹永遠不應該足夠深,以獲得堆棧溢出。 但是,您的聯合功能似乎缺少這種優化。
我曾經為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];
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.