【问题标题】:What is the Time Complexity of Quick Union?快速联合的时间复杂度是多少?
【发布时间】:2017-08-19 13:24:08
【问题描述】:

我正在参加有关数据结构和算法的 coursera 课程。作者提到快速查找是 O(N^2),这是有道理的(假设对 N 个对象的 N 个联合操作可能需要 N*N 数组访问)。但是,我不明白为什么 Quick Union 会更好。似乎在最坏的情况下,一棵狭长的树,对 N 个对象的 N Find 操作也会导致 O(N^2),但材料说它是 O(N)。

所以,一个是二次时间,一个是线性时间。我不确定我是否理解为什么会有差异。示例:

快速查找方法

int[] id = new int[10];

for(int i = 0; i < 10; i++)
    id[i] = i;  

// Quick find approach

int QuickFind(int p)
{
    return id[p];
}

public void Union(int p, int q)
{
    int pId = find(p);
    int qId = find(q);

    if (pId == qId)
        return;

    for (int i = 0; i < id.length; i++)
    {
        if(id[i] == pId)
            id[i] = qId;
    }
}

快速联合方法

int Find(int p)
{
    while(p != id[p])
        p = id[p];

    return p;
}

void QuickUnion(int p, int q)
{
    int pRoot = Find(p);
    int qRoot = Find(q);

    if(pRoot == qRoot)
        return;

    id[pRoot] = qRoot;
}

【问题讨论】:

  • 通常在联合查找数据结构中,会在根中存储一个等级,并且通过将较小等级的根嫁接到较高的根上来执行联合 - 这可以防止长窄树。如果您提供一段简短的代码摘录来演示您正在谈论的内容,以及您认为是 O(N^2) 的特定案例,您的问题会更好。然后有一些具体的答案。
  • Quick Union 实际上会导致 O(N) 查找操作。我认为教科书可能指的是单个查找操作。

标签: algorithm quick-union


【解决方案1】:

我认为 快速查找对 N 个对象进行 N 次联合操作以找到 1,但是 Quick-Union 确实 N 找到对 N 个对象的操作以联合 N 因此,第二个更快

【讨论】:

    【解决方案2】:

    我也遇到过这个。没错,对 N 个对象的 N find 操作也会导致快速联合的 O(N^2)。然而,主要区别在于,使用快速查找时,在执行 union 操作时,您将始终需要遍历所有对象,这对于最坏情况和最佳情况都是如此。

    而使用快速联合不需要遍历所有对象,两个对象的联合可以在恒定时间内完成。

    两种方法都有 O(N^2) 的最坏情况。在某些情况下,快速联合可能会稍微快一些,具体取决于输入的性质。

    这是因为使用快速查找,联合操作的计算复杂度总是大于或等于 N。快速联合不是这种情况,find 操作可以执行小于 N 的计算。

    【讨论】:

      【解决方案3】:
      // Naive implementation of find
      int find(int parent[], int i)
      {
          if (parent[i] == -1)
              return i;
          return find(parent, parent[i]);
      }
      
      // Naive implementation of union()
      void Union(int parent[], int x, int y)
      {
          int xset = find(parent, x);
          int yset = find(parent, y);
          parent[xset] = yset;
      }
      

      上述union()find() 很幼稚,最坏情况的时间复杂度是线性的。为表示子集而创建的树可能是倾斜的,并且可能变得像一个链表。以下是最坏情况的示例。

      Let there be 4 elements 0, 1, 2, 3
      
      Initially all elements are single element subsets.
      0 1 2 3 
      
      Do Union(0, 1)
         1   2   3  
        /
       0
      
      Do Union(1, 2)
           2   3   
          /
         1
       /
      0
      
      Do Union(2, 3)
               3    
              /
            2
           /
         1
       /
      0
      

      在最坏的情况下,上述操作可以优化为O(Log n)。这个想法是总是在更深的树的根下附加更小的深度树。这种技术称为按等级联合。优先使用术语 rank 而不是 height,因为如果使用路径压缩技术(我在下面讨论过),那么 rank 并不总是等于高度。

      Let us see the above example with union by rank
      Initially all elements are single element subsets.
      0 1 2 3 
      
      Do Union(0, 1)
         1   2   3  
        /
       0
      
      Do Union(1, 2)
         1    3
       /  \
      0    2
      
      Do Union(2, 3)
          1    
       /  |  \
      0   2   3
      

      对朴素方法的第二个优化是路径压缩。这个想法是在调用find() 时展平树。当为元素 x 调用 find() 时,将返回树的根。 find() 操作从x 向上遍历找到根。路径压缩的想法是让找到的根成为x的父节点,这样我们就不必再次遍历所有中间节点。如果x 是子树的根,那么x 下所有节点的路径(到根)也会被压缩。

      Let the subset {0, 1, .. 9} be represented as below and find() is called
      for element 3.
                    9
               /    |    \  
              4     5      6
           /     \        /  \
          0        3     7    8
                  /  \
                 1    2  
      
      When find() is called for 3, we traverse up and find 9 as representative
      of this subset. With path compression, we also make 3 as child of 9 so 
      that when find() is called next time for 1, 2 or 3, the path to root is 
      reduced.
      
                     9
               /    /  \    \
              4    5    6     3 
           /           /  \   /  \
          0           7    8  1   2           
      

      这两种技术相辅相成。每个操作的时间复杂度变得比O(logn) ~ O(n)还要小。事实上,摊销时间复杂度实际上变成了一个小常数。

      我没有发布上述优化的代码,因为我猜这是分配部分。希望对您有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-20
        • 2015-01-20
        • 2018-11-24
        • 2014-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-04
        相关资源
        最近更新 更多