Saltar al contenido principal

Union-Find

El algoritmo de Kruskal para encontrar el árbol cobertor mínimo de un grafo crea una cola de prioridad con todas las aristas y parte con un bosque T=T=\emptyset (visto como conjunto de aristas). Luego va tomando cada arista, y si no forma ciclo en el bosque, la agrega a TT, terminando cuando T=n1|T|=n-1 y el bosque se ha convertido en un árbol. En un grafo conexo de nn nodos y n1en2n-1 \le e \le n^2 aristas, el algoritmo tiene un peor caso de O(eloge)=O(elogn)O(e\log e)=O(e\log n) para manejar la cola de prioridad. Sin embargo, en esta formulación no queda claro cómo determinar si una arista forma ciclo o no.

Si pensamos los árboles de TT como clases de equivalencia formadas por nodos, una arista (u,v)(u,v) forma ciclo sii uu y vv son nodos del mismo árbol, es decir, están en la misma clase de equivalencia. Cuando no lo están, agregar la arista (u,v)(u,v) tiene el efecto de unir los dos árboles, es decir, las dos clases de equivalencia. Podemos entonces reexpresar las operaciones que necesitamos como operaciones que manejan clases de equivalencia:

  • Partimos con cada uno de los nn elementos formando su propia clase.
  • Podemos preguntar si dos elementos pertenecen a la misma clase.
  • Podemos unir dos clases.

La interfaz que veremos define un elemento de cada clase, en forma arbitraria pero consistente, como su representante. Tenemos entonces las dos operaciones siguientes:

  • Find(v)Find(v) entrega el representante de la clase de equivalencia de vv.
  • Union(x,y)Union(x,y) une las clases de equivalencia representadas por xx y por yy.

--> imagen

Dos elementos uu y vv pertenecen entonces a una misma clase sii Find(u)=Find(v)Find(u) = Find(v), y para unir las clases de dos elementos cualquiera (no necesariamente representantes de clase) uu y vv realizamos Union(Find(u),Find(v))Union(Find(u),Find(v)). Con esta interfaz, el algoritmo de Kruskal realiza O(e)O(e) operaciones FindFind y O(n)O(n) operaciones UnionUnion. Veremos primero una solución de tiempo O(logn)O(\log n) para estas operaciones y luego una mucho mejor, que requiere análisis amortizado. Con estas soluciones, el costo del algoritmo de Kruskal es O(elogn)O(e\log n), dominado por las operaciones en la cola de prioridad.