Conjuntos disjuntos

Propaganda
MC3305
Algoritmos e Estruturas de Dados II
Aula 19 – Conjuntos disjuntos
(Union-find)
Prof. Jesús P. Mena-Chalco
[email protected]
2Q-2015
1
Números de Ackermann
2
3
Ackermann
A função de Ackermann é definida recursivamente para
números inteiros não negativos, m e n, como:
4
Ackermann
5
Ackermann
Fonte: https://helloacm.com/ackermann-function/
6
7
8
Geralmente a função de
Ackermann é utilizada para
testar um compilador,
quando considerada a
capacidade de otimização
da recursão.
Recursão extrema!
9
Função inversa de Ackermann
10
Conjuntos disjuntos
11
Estruturas para conjuntos disjuntos
 Union-Find
 Coleção
{S1,..., Sk} de conjuntos disjuntos dinâmicos
(que variam ao longo do tempo)
 Cada conjunto Sk é identificado por um representante,
que é um membro do conjunto.
 Geralmente não importa quem é o representante
8
7 3
2
1
9 0
6
5
4
0 1 2 3 4 5 6 7 8 9
C 5 1 1 35 5 5 3 35
12
Operações
 Make_Set(x):
Cria um novo conjunto cujo único
elemento é apontado por x.
–
x não pode pertencer a outro conjunto da coleção.
 Union(x,
y): Executa a união dos conjuntos que
contêm x e y, digamos Sx e Sy, em um conjunto único.
–
Sx ∩ Sy é vazio (conjuntos disjuntos).
–
O representante de S = Sx ∪ Sy é um elemento de S.
 Find(x):
Devolve um ponteiro para o representante
(único) do conjunto que contém x.
13
Aplicações
 Algumas
aplicações envolvem o agrupamento de N
elementos em uma coleção de conjuntos disjuntos,
ou seja, um particionamento dos elementos em
conjuntos.
Alguns usos
–
–
Problemas de grafos
E.g. árvore geradora mínima, componentes conexas
Agrupamento (clustering)
Envolvido em mineração de dados e reconhecimento de padrões
14
Componentes conexas
Determinação das componentes conexas de um grafo G(V,E)
15
Componentes conexas
Componentes_Conexas (G(V,E))
Para cada vértice v ∈ V
Make_Set(v);
Para cada aresta (u,v) ∈ E
Se (Find_Set(u) ≠ Find_Set(v))
Union(u,v);
16
Componentes conexas
Mesma_Componente (u,v)
Se (Find_Set(u) = Find_Set(v))
devolve verdadeiro;
Senão
devolve falso;
17
Componentes conexas
18
Componentes conexas
19
Representação de conjuntos disjuntos
A maneira mais simples de implementar uma estrutura de
dados para conjuntos disjuntos consiste em representá-los
como um vetor onde o índice de cada elemento contém o
representante do conjunto ao qual ele pertence.
8
7 3



2
1
9 0
6
5
4
0 1 2 3 4 5 6 7 8 9
C 5 1 1 35 5 5 3 35
Find_Set (O(1))
Make_Set (O(1))
Union: (O(n)) (todos os elementos de um dos conjuntos
deverão ter seus representantes alterados)
20
Representação de conjuntos disjuntos
Outra maneira simples de implementar uma estrutura de
dados para conjuntos disjuntos consiste em representar cada
conjunto como uma lista encadeada.
–
O primeiro elemento da lista é o representante
Exemplo: S = {a,d,e}
head



tail
Find_Set (O(1))
Make_Set (O(1))
Union?
21
Conjuntos disjuntos com listas encadeadas
Podemos implementar Union(x,y) adicionando a
lista de x no final de y
–
y vira o representante do conjunto
x
y
22
Conjuntos disjuntos com listas encadeadas
Podemos implementar Union(x,y) adicionando a
lista de x no final de y
–
y vira o representante do conjunto
x
y
y
x
23
Conjuntos disjuntos com listas encadeadas
Podemos implementar Union(x,y) adicionando a
lista de x no final de y
–
y vira o representante do conjunto
x
y
y
x
O número de trocas de
ponteiros para o
representante pode ser
quadratica em
relação ao número
de elementos
Problema: Todos os ponteiros dos elementos da lista
de x devem ser apontados para y.
24
Conjuntos disjuntos com listas encadeadas
Exercício: forneça uma sequência de operações
Union em que o número de troca de ponteiros para
o representante seja de ordem quadrática em
relação ao número de elementos (n2)
25
Conjuntos disjuntos com listas encadeadas
Exercício: forneça uma sequência de operações
Union em que o número de troca de ponteiros para
o representante seja de ordem quadrática em
relação ao número de elementos (n2)
26
Conjuntos disjuntos com listas encadeadas
 Instância
–
–
–
–
exemplo
Seja n o numero de operações Make_Set.
Seja m o numero total de operações Union e Make_Set
Suponha que tenhamos X1,...,Xn objetos
Então executamos uma sequência de n operações Make_Set
seguidas por n-1 operações Union, de forma que m = 2n-1.
27
Conjuntos disjuntos com listas encadeadas
n
operações Make_Set (θ(n))
 Pelo fato da i-ésima operação Union atualizar i
objetos, o número total de objetos atualizados
por todas as n-1 operações Union é θ(n2)
n-1
 Número total de operações = θ(n + ∑ i) = θ(n+n2)
= θ(n2)
i=1
28
Conjuntos disjuntos com listas encadeadas
n
operações Make_Set (θ(n))
 Pelo fato da i-ésima operação Union atualizar i
objetos, o número total de objetos atualizados
por todas as n-1 operações Union é θ(n2)
n-1
 Número total de operações = θ(n + ∑ i) = θ(n+n2)
= θ(n2)
i=1
Como resolver o problema da União?
Heurística da união ponderada
29
Heurística da união ponderada
30
Heurística da união ponderada
 De
acordo com a implementação anterior, cada
operação Union leva tempo médio θ(n) pela
possibilidade de inserir uma lista mais longa em uma
lista pequena.
 Uma
alternativa para melhorar a complexidade é
adotar a heurística da união ponderada:
–
–
Cada representante armazena o comprimento da lista
de elementos do seu conjunto
A inserção é sempre feita da lista menor na lista maior
31
Heurística da união ponderada
 De
acordo com a implementação anterior, cada
operação Union leva tempo médio θ(n) pela
possibilidade de inserir uma lista mais longa em uma
lista pequena.
 Uma
alternativa para melhorar a complexidade é
adotar a heurística da união ponderada:
–
–
Cada representante armazena o comprimento da lista
de elementos do seu conjunto
A inserção é sempre feita da lista menor na lista maior
 Exercício:
pensem em uma sequência de
operações Union de melhor caso e em outra de pior
caso.
32
Heurística da união ponderada

Melhor caso: um dos conjuntos tem sempre tamanho 1
–
–
Cada operação envolve apenas a atualização de ponteiros de
um único elemento.
n operações union: θ(1)*n = θ(n)
33
Heurística da união ponderada

Melhor caso: um dos conjuntos tem sempre tamanho 1
–
–

Cada operação envolve apenas a atualização de ponteiros de
um único elemento.
n operações union: θ(1)*n = θ(n)
Pior caso: os dois conjuntos tem sempre tamanhos
idênticos.
...
4*(n/8)
2*(n/4)
1*(n/2)
h
∑(n/2)
i=1
h = log2n
θ(n log n)
34
Heurística da união ponderada
 Pergunta:
É possível fazer com que a união seja mais eficiente
usando outra estrutura de dados?
35
Heurística da união ponderada
 Pergunta:
É possível fazer com que a união seja mais eficiente
usando outra estrutura de dados?
 Resposta:
Sim! Floresta de conjuntos disjuntos
36
Conjuntos disjuntos
37
Floresta de conjuntos disjuntos
 Representação
por meio de árvores
 A raiz da árvore contém o representante do conjunto
 O filho aponta para o pai
União
38
Floresta de conjuntos disjuntos

Na forma apresentada, a estrutura é tão lenta quanto aquela que
utiliza listas encadeadas.

Make_Set: cria uma árvore com um único vértice (θ(1))

Find_Set: segue os ponteiros para os pais até atingir a raiz (θ(n))

Union: faz a raiz de uma árvore apontar para a raiz da outra
–
–
exige saber quem são as raizes das árvores dos dois elementos, ou seja,
envolve 2 operações Find_Set
(θ(n))
Ou seja, no total, n operações Union tem complexidade (θ(n2))
39
http://www.cs.usfca.edu/~galles/JavascriptVisual/DisjointSets.html
40
Heurística para floresta de conjuntos
disjuntos
 União
ponderada (union by rank): faça a raiz da
árvore com menor rank (altura) apontar para a raiz da
árvore com maior rank.
41
Heurística para floresta de conjuntos
disjuntos
 União
ponderada (union by rank): faça a raiz da
árvore com menor rank (altura) apontar para a raiz da
árvore com maior rank.
 Compressão
de caminhos (path compression):
durante uma busca (Find_Set) faça os nós do
caminho apontar para a raiz
Find_Set(a)
42
Heurística para floresta de conjuntos
disjuntos
 Compressão
de caminhos (path compression):
durante uma busca (Find_Set) faça os nós do
caminho apontar para a raiz
0
4
1
2
5
6
0
3
7
8
9
4
10
1
2
3
5
6
7
8
9
10
Find_Set(9)
43
Implementação envolvendo união
ponderada e compressão de caminhos
Make_Set (x)
p[x] = x;
rank[x] = 0;
Find_Set (x)
se x ≠ p[x]
p[x] = Find_Set(p[x]);
devolve p[x];
Union (x, y)
x = Find_Set(x);
y = Find_Set(y);
se rank[x] > rank[y]
p[y] = x;
senão
p[x] = y;
se rank[x] == rank[y]
rank[y]++;
44
Heurística para floresta de conjuntos
disjuntos
Separadamente, ambas as heurísticas melhoram o
tempo de execução das operações
 Sozinha,
a heurística da union by rank induz o
mesmo tempo de execução da heurística de união
ponderada usada na representação por listas ligadas
(θ(n log n))
 Sozinha,
a heurística de compressão de caminho
induz tempo de execução (n + f log(n)) para f < n
onde f é o número de operações Find_Set
45
Heurística para floresta de conjuntos
disjuntos
 Quando
ambas as heurísticas são aplicadas, o
tempo de execução se torna θ(n α(n)), em que α(n)
é o inverso da função de Ackermann
 Função
–
de Ackermann
Para k ≥ 0 e j ≥ 1 inteiros, define-se Ak(j) como:
46
Heurística para floresta de conjuntos
disjuntos
 Função
de Ackermann
–
A0(j) = j+1
–
Ai+1(j) = Ai(Ai(Ai...(j))), sendo Ai aplicado j vezes
–
A1(j) = 2j+1
–
A2(j) = A1(A1(A1...(j))) = 2j+1
–
A3(j) = A2(A2(A2...(j))) = 2^(2^(2^...(j)))
j+1
 Função
de Ackermann inversa
α(n) = min{k : Ak(1) ≥ n} =
0 para 0 ≤ n ≤ 2
1 para n = 3
2 para 4 ≤ n ≤ 7
3 para 8 ≤ n ≤ 2047
4 para 2048 ≤ n ≤ 22048
47
Heurística para floresta de conjuntos
disjuntos
 Quando
ambas as heurísticas são aplicadas, o
tempo de execução se torna θ(n α(n)), em que α(n)
é o inverso da função de Ackermann
 Para
todos os fins práticos, podemos considerar
α(n) ≤ 4
–
θ(n)
48
Heurística para floresta de conjuntos
disjuntos
49
http://www.cs.usfca.edu/~galles/JavascriptVisual/DisjointSets.html
50
Exercício

Exercício (21.2-2 do Cormen 2nd Ed): Mostre a estrutura de
dados resultante e as respostas devolvidas pelas
operações Find_Set no seguinte programa, usando
a) lista ligada com heurística de união ponderada
b) floresta de conjuntos disjuntos com união ponderada e compressão
de caminhos
– (assuma que, caso os conjuntos contendo i e j sejam do mesmo
tamanho, Union(i,j) concatena a lista de j na lista de i)
for (i = 1; i <= 16; i++)
Make_Set(i);
for (i = 1; i <= 15; i = i + 2)
Union(i,i+1);
for (i = 1; i <= 13; i = i + 4)
Union(i,i+2);
Find_Set(2);
Find_Set(9);
51
Árvore geradora mínima (Kruskal)
52
53
Download