Quick Union Java实现

时间:2017-05-03 16:55:01

标签: java

我一直在研究快速联合算法。下面的代码是实现的示例。 有人可以向我解释 root方法中发生了什么?

public class quickUnion {
    private int[] id;

    public void QuickUnionUF(int N){
        id = new int [N];
        for(int i = 0; i < N; i++){
            id[i] = i;
        }
    }

    private int root(int i){
        while (i != id[i]){
            i = id[i];
        }
        return i;
    }
    public boolean connected(int p, int q){
        return root(p) == root(q);
    }
    public void union(int p, int q){
        int i = root(p);
        int j = root(q);
        id[i] = j;
    }
}

5 个答案:

答案 0 :(得分:2)

union find的核心原则是每个元素都属于一个不相交的元素集。这意味着,如果你绘制一个森林(一组树),森林将包含所有元素,并且没有元素将在两个不同的树中。

构建这些树时,您可以想象任何节点都有父节点或根节点。在union find的这个实现中(以及在大多数union find实现中),每个元素的父元素都存储在该元素索引的数组中。因此,相当于id [i]的元素是i的父元素。

您可能会问:如果我没有父母(也就是根),该怎么办?在这种情况下,惯例是将i设置为自身(我是它自己的父)。因此,id [i] ==我只是检查我们是否已到达树的根。

将所有这些放在一起,根函数从起始节点遍历树(父对象)直到它到达根。然后它返回根。

暂且不说: 为了使这个算法更快地到达根,一般实现将“压扁”树:你需要通过根目录所需的父亲越少,根函数返回的速度就越快。因此,在许多实现中,您将看到另一个步骤,其中您将元素的父级设置为其原始祖父级(id [i] = id [id [i]])。

答案 1 :(得分:1)

这里算法的要点是:始终保持一个顶点的根等于它自己。

  1. 初始化:初始化ID [i] = i。每个顶点本身都是一个根。
  2. 合并根目录

    • 如果我们合并root 5和root 6.假设我们想要将root 6合并到root 5.所以id [6] = 5. id [5] = 5. - &gt; 5是root。
    • 如果我们继续合并4到6. id [4] = 4 - &gt;基础。 id [6] = 5. - &gt;不是基础。我们继续发现:id [5] = 5 - &gt;基础。所以我们分配id [4] = 6
  3. 在所有情况下,我们始终保持惯例:如果x是基础根,id[x] == x这是算法的要点。

答案 2 :(得分:0)

从课程Union find

中提供的Pdf文件

我的根是id [id [id [... id [i] ...]]]。

根据给定的例子

  public int root(int p){

  while(p != id[p]){

      p = id[p];    
  }
  return p;
  }

让我们考虑一下情况:

enter image description here

id []的元素看起来像enter image description here

现在让我们来电话

    root(3)

根法中循环的干运行是:

enter image description here

答案 3 :(得分:0)

要了解 root 方法的作用,需要了解这种数据结构如何帮助将值组织成不相交的集合。

它通过构建树来实现。每当两个独立的值 ? 和 ? 被认为属于同一个集合时, ? 就成为 ? 的孩子(然后是 ? 的父母)。然而,如果 ? 已经有一个父级,那么我们首先移动到 ? 的那个父级,以及那个父级的父级,...直到我们找到一个没有父级的祖先。这是root(p),我们称之为?'。如果它有父级,我们对 ? 做同样的事情。让我们称那个祖先为?'。最后,?'变成了一个孩子?'。通过这样做,我们隐式地使原始 ? 和 ? 成员成为同一棵树的成员。

我们怎么知道?和?是同一棵树的成员?通过查找他们的根源。如果它们碰巧有相同的根,那么它们必然在同一棵树中,即它们属于同一个集合。

示例

让我们看一个示例运行:

QuickUnionUF array = new QuickUnionUF(10);

这将创建以下数组:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

这个数组代表。边的from侧是数组中的索引(0..9),同一边的to侧是value< /em> 在该索引处找到(也是 0..9)。如您所见,数组以所有边都是自引用(循环)的方式初始化。你可以说每个值都是它自己的树的根(没有其他值)。

对任何值 0..9 调用 root 将返回相同的数字,因为对于所有 i 我们有 id[i] == i。所以在这个阶段 root 并没有给我们太多。

现在,让我们指出两个值实际上属于同一个集合:

array.union(2, 9); 

这将导致赋值id[2] = 9,所以我们得到这个数组:

[0, 1, 9, 3, 4, 5, 6, 7, 8, 9]

图形上,这个建立的链接表示为:

       9
      /
     2

如果现在我们调用 root(2),我们将得到 9 作为返回值。这告诉我们 2 与 9 在同一个集合(即树)中,而 9 恰好获得了该树的 root 角色(这是一个任意选择;它也可能是 2) .

让我们也将 3 和 4 链接在一起。这是一个与上面非常相似的案例:

array.union(3, 4);

这会分配 id[3] = 4 并导致此数组和树表示:

[0, 1, 9, 4, 4, 5, 6, 7, 8, 9]

       9         4
      /         / 
     2         3

现在让我们让它更有趣。让我们指出 4 和 9 属于同一个集合:

array.union(4, 9);

仍然 root(4)root(9) 只是返回相同的数字(4 和 9)。还没有什么特别的...任务是id[4] = 9。这导致了这个数组和图表:

[0, 1, 9, 4, 9, 5, 6, 7, 8, 9]

       9
      / \ 
     2   4
        /
       3

注意这个单一的分配是如何将两棵不同的树连接成一棵树的。如果现在我们要检查 2 和 3 是否在同一棵树中,我们调用

if (connected(2, 3)) /* do something */

虽然我们从来没有明确说过 2 和 3 属于同一个集合,但应该从前面的动作中暗示出来。 connected 现在将使用对 root 的调用来暗示这一事实。 root(2) 将返回 9,root(3) 将返回 9。我们可以看到 root 在做什么......它在图中向上走向它的树的根节点是在。该数组具有进行该行走所需的所有信息。给定一个 index,我们可以读取该数字的 parent(索引)数组。这可能必须重复才能到达祖父母,......等等:它可以是短途或长途步行,具体取决于给定节点与其所在树的根之间有多少“边”。

答案 4 :(得分:-2)

/**
 * Quick Find Java Implementation Eager's Approach
 */
package com.weekone.union.quickfind;

import java.util.Random;

/**
 * @author Ishwar Singh
 *
 */
public class UnionQuickFind {

    private int[] itemsArr;

    public UnionQuickFind() {
        System.out.println("Calling: " + UnionQuickFind.class);
    }

    public UnionQuickFind(int n) {
        itemsArr = new int[n];
    }

    // p and q are indexes
    public void unionOperation(int p, int q) {

        // displayArray(itemsArr);
        int tempValue = itemsArr[p];
        if (!isConnected(p, q)) {
            itemsArr[p] = itemsArr[q];
            for (int i = 0; i < itemsArr.length; i++) {
                if (itemsArr[i] == tempValue) {
                    itemsArr[i] = itemsArr[q];
                }
            }
            displayArray(p, q);
        } else {
            displayArray(p, q, "Already Connected");
        }

    }

    public boolean isConnected(int p, int q) {
        return (itemsArr[p] == itemsArr[q]);
    }

    public void connected(int p, int q) {

        if (isConnected(p, q)) {
            displayArray(p, q, "Already Connected");
        } else {
            displayArray(p, q, "Not Connected");
        }
    }

    private void displayArray(int p, int q) {
        // TODO Auto-generated method stub
        System.out.println();
        System.out.print("{" + p + " " + q + "} -> ");
        for (int i : itemsArr) {
            System.out.print(i + ", ");
        }
    }

    private void displayArray(int p, int q, String message) {
        System.out.println();
        System.out.print("{" + p + " " + q + "} -> " + message);

    }

    public void initializeArray() {
        Random random = new Random();
        for (int i = 0; i < itemsArr.length; i++) {
            itemsArr[i] = random.nextInt(9);
        }
    }

    public void initializeArray(int[] receivedArr) {
        itemsArr = receivedArr;
    }

    public void displayArray() {
        System.out.println("INDEXES");
        System.out.print("{p q} -> ");
        for (int i : itemsArr) {
            System.out.print(i + ", ");
        }
        System.out.println();
    }

}


Main Class:- 

/**
 * 
 */
package com.weekone.union.quickfind;

/**
 * @author Ishwar Singh
 *
 */
public class UQFClient {

    /**
     * @param args
     */
    public static void main(String[] args) {

        int[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        int n = 10;
        UnionQuickFind unionQuickFind = new UnionQuickFind(n);
        // unionQuickFind.initializeArray();
        unionQuickFind.initializeArray(arr);
        unionQuickFind.displayArray();
        unionQuickFind.unionOperation(4, 3);
        unionQuickFind.unionOperation(3, 8);
        unionQuickFind.unionOperation(6, 5);
        unionQuickFind.unionOperation(9, 4);
        unionQuickFind.unionOperation(2, 1);
        unionQuickFind.unionOperation(8, 9);
        unionQuickFind.connected(5, 0);
        unionQuickFind.unionOperation(5, 0);
        unionQuickFind.connected(5, 0);
        unionQuickFind.unionOperation(7, 2);
        unionQuickFind.unionOperation(6, 1);
    }

}

输出:

INDEXES

{p q} -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 

{4 3} -> 0, 1, 2, 3, 3, 5, 6, 7, 8, 9, 

{3 8} -> 0, 1, 2, 8, 8, 5, 6, 7, 8, 9, 

{6 5} -> 0, 1, 2, 8, 8, 5, 5, 7, 8, 9, 

{9 4} -> 0, 1, 2, 8, 8, 5, 5, 7, 8, 8, 

{2 1} -> 0, 1, 1, 8, 8, 5, 5, 7, 8, 8, 

{8 9} -> Already Connected

{5 0} -> Not Connected

{5 0} -> 0, 1, 1, 8, 8, 0, 0, 7, 8, 8, 

{5 0} -> Already Connected

{7 2} -> 0, 1, 1, 8, 8, 0, 0, 1, 8, 8, 

{6 1} -> 1, 1, 1, 8, 8, 1, 1, 1, 8, 8,