1. 程式人生 > >並查集資料結構的幾種實現

並查集資料結構的幾種實現

第一種實現

每一個節點都只是指向根節點

find是 常數時間複雜度的, union是 線性時間複雜度的。

class quickFind {
  int[] a;
  int count;

  void init (int N) {
    a = new int[N];
    for (int i = 0; i < N; i++) {
      a[i] = i;
    }
    count = N;
  }
  boolean connected(int p , int q) {
    return find(p) == find(q);
  }
  int find (int
p) { return a[p]; } void union(int p , int q) { int proot = find(p); int qroot = find(q); if (proot == qroot) { return; } for (int i = 0; i < a.length; i++) { if (a[i] == proot) { a[i] = qroot; } } count--; } }

 

 

第二種實現

每一個節點指向一個和自己在相同集合中的節點

find操作是樹的高度時間複雜度,union操作也是 樹的高度時間複雜度

 

class quickUnion {
  int[] a;
  int count;

  void init(int N) {
    a = new int[N];
    for (int i = 0; i < N; i++) {
      a[i] = i;
    }
    count = N;
  }

  void find(p) {
    while (p != a[p]) p = a[p];
    return p;
  }

  
void union(int p, int q) { int proot = find(p); int qroot = find(q); if (proot == qroot) { return; } a[proot] = qroot; count--; } void connected(int p, int q) { return find(p) == find(q); } }

 

第三種實現其實是第二種實現的改良版本

因為第二種實現,當樹的高度比較大,趨於連結串列的時候,時間複雜度會比較高,應該儘量減小樹的高度

find時間複雜度logn,union時間複雜度logn

 

class quickUnion2 {
  int[] a;
  int count;
  int[] size;

  void init(int N) {
    a = new int[N];
    size = new int[N];
    for (int i = 0; i < N; i++) {
      a[i] = i;
      size[i] = 1;
    }
    count = N;
  }

  void find(p) {
    while (p != a[p]) p = a[p];
    return p;
  }

  void union(int p, int q) {
    int proot = find(p);
    int qroot = find(q);
    if (proot == qroot) {
      return;
    }
    if (size[proot] < size[qroot]) {
      a[proot] = qroot;
      size[qroot] += size[proot];
    } else {
      a[qroot] = proot;
      size[proot] += size[qroot];
    }
    count--;
  }
  void connected(int p, int q) {
    return find(p) == find(q);
  }
}

 

使用場景,比如 島嶼個數 問題,除了用深度優先搜尋之外,還可以用 並查集資料結構來做。