• Nenhum resultado encontrado

INF 1010 Estruturas de Dados Avançadas

N/A
N/A
Protected

Academic year: 2022

Share "INF 1010 Estruturas de Dados Avançadas"

Copied!
45
0
0

Texto

(1)

INF 1010

Estruturas de Dados Avançadas

Grafos

(2)

árvores geradoras

suponha G = (V, E, p) um grafo conexo

Uma árvore geradora é um subgrafo acíclico de G contendo todos os vértices e com caminhos entre quaisquer 2 vértices

06/17/2019

(3)

árvore geradora mínima (MST)

Árvore geradora de custo mínimo

Dado um grafo ponderado G = (V,E,p),

uma árvore geradora de custo mínimo para G é uma árvore tal que:

V é o conjunto de nós da árvore

A soma dos pesos das arestas é minima (entre as árvores geradoras)

06/17/2019

(4)

Algoritmo de Kruskal

Algoritmo de Kruskal

Entrada: Um grafo ponderado G = (V,E,p) Saída: Árvore geradora de custo mínimo

1.

Considere cada nó em V como

uma árvore separada (formando uma floresta)

2.

Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3.

Repita o Passo (2) até todos os nós estarem conectados.

06/17/2019

(5)

Algoritmo de Kruskal

1. Considere cada nó como uma árvore separada (formando uma floresta)

06/17/2019

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

0 5

1

2

3 4

6

(6)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

06/17/2019

0 5

1

2

3 4

6 0 10

5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(7)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

06/17/2019

0 5

1

2

3 4

6

10

12

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(8)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

06/17/2019

0 5

1

2

3 4

6

10

14

12

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(9)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

06/17/2019

0 5

1

2

3 4

6

10

14 16

12

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(10)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

06/17/2019

0 5

1

2

3 4

6

10

14 16

18 12

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(11)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

06/17/2019

0 5

1

2

3 4

6

22 10

14 16

12

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(12)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

0 5

1

2

3 4

6

22 24 10

14 16

12

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(13)

Algoritmo de Kruskal

2. Examine a aresta de menor custo.

Se ela unir duas árvores na floresta, inclua-a.

3. Repita o Passo (2) até todos os nós estarem conectados.

0 5

1

2

3 4

6

25

22 10

14 16

12

0 5

1

2

3 4

6

25

22 24 10

14 28

16

18 12

(14)

implementação

grafo continua representado como antes

heap de prioridades para arestas

minheap para remover aresta de menor custo

mas como descobrir se a aresta de menor custo une 2 árvores distintas?

(15)

como descobrir se uma aresta “conecta” duas árvores?

• uso de uma estrutura de dados específica chamada união e busca

• estrutura de dados para manipulação de

partições de conjuntos

(16)

Definições

Universo: U = {x

1

,x

2

,…,x

n

}

Uma partição é uma coleção : C = {S

1

,…,S

k

} de conjuntos disjuntos

S

i

U para qualquer i ⊆ S

1

∪ … S ∪

k

= U

(cobertura)

S

i

S ∩

j

= , para i≠j ∅

(disjunção)

partição S

i

identificada por

um de seus elementos x S ∈

i (REPRESENTANTE)

(17)

Operações Básicas

cria():

cria uma partição do conjunto original

busca(x):

Informa qual partição um elemento faz parte,

retornando um elemento que representa a partição Útil para determinar se dois elementos estão no mesmo

conjunto

{k,j,n,o,y,w,x,z} -> w

união(x,y):

combina dois conjuntos em um único, substituindo Si e Sj

por um novo conjunto Sk tal que Si S j = Sk

(18)

unindo partes

(19)

Representação de estruturas de união

e busca

(20)

Representação por árvores reversas

Árvores reversas (Reversed Trees)

Cada nó aponta para o seu pai

a raiz aponta para si mesma ou aponta para NULL

Depois de um nó deixar de ser a raiz, um nó nunca pode se tornar uma raiz novamente

x

s w

x

s w

x

y w

x

y w

(21)

Representação por Árvores Reversas

Exemplo

S

1

= {t,u,v,y,z} S

2

= {s,w,x}

v u

z y

t

x

s w

u

t v y z s w

x

(22)

Operações

cria(n) = {S

0

, …, S

n-1

}

cria uma estrutura uniao-e-busca com n elementos disjuntos

v u

t y s w

t u v y z

s w x

(23)

Operações

busca(ub, x)

retorna o elemento que representa o conjunto busca a raiz da árvore que contém o elemento

v u

z y

t

x

s w

u

t v y z s

x

busca(y) -> u busca(s) -> x

w

(24)

Operações

união(ub, u, x)

une dois grupos, fazendo com que a raiz de um grupo aponte para a raiz do outro grupo

torna uma árvore uma sub-árvore da outra

união(ub, u, x) = {t,u,v,y,z, s,w,x}

À medida que novas uniões são realizadas, uma árvore completamente degenerada pode ser criada, fazendo com que as operações de Find se realizem em tempo linear O(n)

v u

z y

t

x

s w

u

t v y z s w

x

(25)

Representação por Vetor

(26)

Representação por Vetor

Implementação de partições:

Através de um vetor

Cada elemento do vetor representa um elemento do universo

Cada elemento do vetor aponta para seu pai

(27)

Representação por Vetor

Exemplo

(Note que a raiz possui -1 como valor do ponteiro)

7 v

u

z y

t

x

s w

2

0 4 5 7 1 6

3

0 1

2 3

2 3

-1 -1

4 5

2 2

6 7

3 2

(28)

União e Busca para uso no lab 11

typedef struct suniaoBusca UniaoBusca;

UniaoBusca* ub_cria(int tam);

/* cria particao de conjunto com tam elementos */

/* cada elemento está inicialmente em parte separada */

int ub_busca (UniaoBusca* ub, int u);

/* retorna o representante da parte em que está u */

int ub_uniao (UniaoBusca* ub, int u, int v);

/* retorna o representante do resultado */

void ub_libera (UniaoBusca* ub);

/* libera a estrutura */

void debug (UniaoBusca *ub);

(29)

idéia da fç arvoreCustoMinimo

(30)

Union-Find p/ Kruskal (

implementação simplificada – ineficiente!!!

)

typedef struct uniaobusca UniaoBusca;

struct uniaoBusca { int n; int *v;

};

UniaoBusca* cria(int size) {

/* aloca novo item com tamanho dado e preenche vetor com -1 */

}

int uniao (UniaoBusca* ub, int u, int v) {

v = busca (ub, v); /* acha raiz de árvore de v */

u = busca (ub, u);

ub->v[u] = v;

return v;

}

(31)

Union-Find p/ Kruskal (

implementação simplificada – ineficiente!!!

)

typedef struct uniaobusca UniaoBusca;

struct uniaoBusca { int n; int *v;

};

UniaoBusca* cria(int size) {

/* aloca novo item com tamanho dado e preenche vetor com -1 */

}

int uniao (UniaoBusca* ub, int u, int v) {

v = busca (ub, v); /* acha raiz de árvore de v */

u = busca (ub, u);

ub->v[u] = v;

return v;

}

(32)

Union-Find p/ Kruskal (

implementação simplificada – ineficiente!!!

)

typedef struct uniaobusca UniaoBusca;

struct uniaoBusca {int n; int *v;};

UniaoBusca* cria(int size) {

/* aloca novo item com tamanho dado e preenche vetor com -1 */

}

int busca (UniaoBusca* ub, int u){

while (ub->v[u] >= 0) u = ub->v[u];

return u;

}

int uniao (UniaoBusca* ub, int u, int v) { ...

}

(33)

União

d

e f

a

b c

j

k l

g

h i

p

q r

m

n o

(34)

União

d

e f

a

b c

j

k l

g

h i

p

q r

m

n o

d

e f

a

c

j

k l

g

h i

p

q r

m

n o

b

(35)

União

À medida que novas uniões são realizadas, uma árvore completamente degenerada pode ser criada, fazendo com que as operações de Find se realizem em tempo linear O(n)

b

d

e f

a

c

j

k l

g

h i

p

q r

m

n o

b

d

e f

a

c

j

k l

g

h i

p

q r

m

n o

(36)

Problema

Configuração inicial:

uma floresta com n nós (singletons)

Operações;

União dos elementos em ordem

uniaoSimples(1,2), uniaoSimples(2,3), ..., uniaoSimples(n-1, n)

Resultado:

uma árvore degenerada busca muito cara!!!

10 9

8 7 6 5 4 3 2 1

(37)

otimizações

(38)

otimizações

na união busca raizes

void uniao (UniaoBusca* ub, int u, int v){

u = busca(ub, u);

v = busca(ub, v);

/* une u e v! */

}

(39)

união nas raizes

39 void uniao (UniaoBusca* ub, int u, int v){

u = ub_busca(ub, u);

v = ub_busca(ub, v);

/* une u e v! */

}

7

v u

z y

t

x

s w

2

0 4 5 7

1 6

3

ou

v 7 u

z y

t x

s w

2

0 4 5 7

1 6

3

(40)

união nas raizes

pendurar árvore com menor número de nós

void uniao (UniaoBusca* ub, int u, int v){

u = busca(ub, u);

v = busca(ub, v);

if (u==v) return;

/* uniao com base no numero de nós */

if /* arvore em u tem menos nós */ { ub->v[u] = v;

/* atualiza o numero de nós de v */

}

else /* arvore em v tem menos nós */

}

como manter o número de nós em cada árvore

(41)

união nas raizes

pendurar árvore com menor número de nós

void uniao (UniaoBusca* ub, int u, int v){

u = busca(ub, u);

v = busca(ub, v);

if (u==v) return;

/* uniao com base no numero de nós */

if /* arvore em u tem menos nós */ { ub->v[u] = v;

/* atualiza o numero de nós de v */

}

else /* arvore em v tem menos nós */

}

como manter o número de nós em cada árvore

podemos usar o próprio campo que indica o pai e em vez de -1 armazenar –(número de nós) em cada raiz

(42)

união nas raizes

”pendurar” árvore com menor número de nós na outra

void uniao (UniaoBusca* ub, int u, int v){

u = busca(ub, u);

v = busca(ub, v);

if (u==v) return;

/* uniao com base no numero de nós */

if (ub->v[u] < ub->v[v]) { ub->v[v] += ub->v[u];

ub->v[u] = v;

return v;

}

else /* arvore em v tem menos nós */

}

(43)

otimizações

na união busca raizes

 mas agora união fica cara

como melhorar isso?

na busca podemos “aproveitar” para pendurar nós intermediários diretamente na raiz

(44)

otimizações

typedef struct uniaobusca UniaoBusca;

struct uniaoBusca {int n; int *v;};

int busca (UniaoBusca* ub, int u){

while (ub->v[u] >= 0) u = ub->v[u];

return u;

}

(45)

otimizações

int busca (UniaoBusca* ub, int u){

int x = u;

int aux;

if ((u < 0) || (u > ub->n)) return -1;

while (ub->v[u] >= 0) u = ub->v[u];

while (ub->v[x] >= 0) { aux = x;

x = ub->v[x];

ub->v[aux] = u;

}

return u;

}

Referências

Documentos relacionados

Um grafo (ou um grafo não orientado) G consiste de um conjunto V de vértices (ou nós) e um conjunto E de arestas (ou arcos) tal que cada aresta e ∈ ∈ E é associada com um par

A leitura é uma atividade que pode ser explicada por diferentes perspectivas teóricas. Nesta aula aprendemos que diferentes perspectivas teóricas explicam o processo de leitura:

A começar pela literatura infantil, passando pelos desenhos animados á televisão e ao cinema, os personagens oferecem imagens que são muito significativas para

(encontrar uma árvore geradora máxima), como você pode usar os algoritmos de Kruskal e Prim (sem alterá-los) para obter uma árvore. • Supondo que todas as arestas de um grafo

Os dados serão adicionados no fim do arquivo (“append“) se ele já existir, ou um novo arquivo será criado, no caso de arquivo não existente anteriormente. • “rb“: Abre

• Caso seja necessário unir todos os elementos e depois verificar cada um a que conjunto ele pertence, todos os elementos precisaria sofrem um Union e depois um Find. • O tempo de

Ao longo de fevereiro, primeiro mês de atividade parlamentar de 2020, Carla Zambelli foi a mais influente nas redes, seguida de dois colegas de partido: o

Entretando, para assegurar a sustentabilidade da bacia outras ações reguladores podem ser desenvolvidas como: realizar os estudos aqui feitos com outros níveis