Você está na página 1de 11

UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE

DEPARTAMENTO DE INFORMTICA E MATEMTICA


APLICADA
PROGRAMA DE PS-GRADUAO STRICTO SENSO
DISCIPLINA DE ALGORITMOS E ESTRUTURAS DE DADOS
EM GRAFOS

Relatrio sobre Implementao do Algoritmo Kruskal

RAIMUNDO LEANDRO ANDRADE MARQUES

Lista de Figuras
Figura 1: Grafo (esquerda) e sua rvore Geradora Mnima (Direita).......................................... 3
Figura 2: conjunto-disjunto inicial contendo 8 arvores ou singletons.......................................... 4
Figura 3: conjunto-disjunto aps algumas operaes contendo trs arvores................................ 4
Figura 4: operao makeset. ......................................................................................................... 5
Figura 5: operao union(x, y). .................................................................................................... 5
Figura 6: operao find(x)............................................................................................................ 5
Figura 7: Pseudocdigo para o algoritmo de Kruskal .................................................................. 6
Figura 8: Encontrando A rvore Geradora Mnima atravs do algoritmo de Kruskal. ............... 7

Introduo
O Algoritmo de Kruskal um algoritmo utilizado para encontrar rvores
Geradoras Mnimas ou AGMs. Em um grafo ponderado ( , ), onde o nmero de
vrtices e o nmero de arestas, uma AGM o caminho simples (sem existncia de
ciclos) que liga todos os vrtices, tal que a , de , onde o peso de cada aresta, tal
que a minimizado. Essas arvores tm diversas aplicaes no mundo real, desde o
desenho de placas de circuito at a elaborao de rotas de comrcio.
Este trabalho se prope a apresentar uma comparao entre o algoritmo de Kruskal
implementado com Conjuntos-Disjuntos e com Matrizes de Adjacncia, e est organizado
da seguinte forma: primeiro sero apresentadas revises sobre rvores Geradoras
Mnimas, Conjuntos-Disjuntos e o Algoritmo de Kruskal, em seguida, teremos uma
explicao sobre o esquema utilizado na implementao e por fim uma concluso sobre
a realizao da tarefa e os resultados obtidos.

rvores Geradoras Mnimas


Em um grafo = ( , ), onde o conjunto de vrtices, o conjunto de
arestas, e para cada aresta ( , ) , existe um peso ( , ) especificando um custo
existente para conectar os vrtices e . um subconjunto acclico tal que
conectando todos os vrtices de e cujo peso total

( ) = (

, )

( , ) (1)

minimizado. J que T acclico e conecta todos os vrtices, ele forma uma rvore, a
qual chamamos rvore geradora, e j que ele gera o grafo G. Dizemos que o problema
para determinar a arvore T chamado problema da rvore geradora mnima [1].

Figura 1: Grafo (esquerda) e sua rvore Geradora Mnima (Direita).


kruskal/graph_and_span_tree.gif

rvores geradoras mnimas so usadas em diversas aplicaes no mundo real.


Dentre elas podemos citar: i) o desenho de circuitos, onde os componentes seriam os
vrtices e as trilhas seriam as arestas, e o problema seria encontrar um design que
minimizasse o uso de cobre para confeco das trilhas [1]; ii) roteamento: no qual os
vrtices seriam as origens e destinos e as arestas seriam as rotas entre eles, o problema
seria encontrar um caminho que minimizasse, por exemplo, o combustvel gasto para
trafegar entre eles; iii) Segmentao de imagens: onde as cores, no modelo RGB, so
usadas como vrtices e as arestas seriam as distncias entre elas, nesse caso, o problema
seria a simplificao de cores da imagem original [2]. Alm de muitos outros.
Neste trabalho usaremos o algoritmo de Kruskal para resolver esse problema, ele
considerado um algoritmo guloso, tendo em vista que ele sempre procura a prxima
aresta com menor peso disponvel no grafo. Trataremos desse algoritmo numa sesso
especfica deste trabalho.

Conjuntos-Disjuntos
Em computao, um conjunto-disjunto uma estrutura de dados, onde elementos
com caractersticas em comum so particionados em um nmero especfico de
subconjuntos. Podemos pensar nos conjuntos-disjuntos como florestas, nas quais suas
arvores so subconjuntos com ns em comum, do contrrio, as arvores apresentaram
apenas seu n raiz, tambm chamado singleton.

Figura 2: conjunto-disjunto inicial contendo 8 arvores ou singletons.


Fonte: http://en.wikipedia.org/wiki/File:Dsu_disjoint_sets_init.svg

Figura 3: conjunto-disjunto aps algumas operaes contendo trs arvores.


Fonte: http://en.wikipedia.org/wiki/File:Dsu_disjoint_sets_final.svg

A estrutura suporta as seguintes operaes bsicas:

makeset(x): Essa operao recebe um elemento e cria uma rvore de rank 0 cujo
n raiz o prprio elemento , ou em outras palavras um conjunto do tipo { }.

Figura 4: operao makeset.


Fonte: A Potential-Based Amortized Analysis of the Union-Find Data Structure.

union(x, y): Essa operao combina a arvore de raiz , com a arvore de raiz ,
atravs da heurstica de unio por rank, Como vimos anteriormente a operao
makeset(x) define o rank de como 0. Assim, quando unimos com , fazemos
o n com
menor, filho do n com
maior. E atualizamos o
do n
escolhido como raiz.

Figura 5: operao union(x, y).


Fonte: A Potential-Based Amortized Analysis of the Union-Find Data Structure.

find(x): Essa operao segue todos os ns a partir de at sua raiz. Durante essa
fase, usamos uma heurstica chamada compresso de caminho, onde fazemos cada
n entre o n e sua raiz, apontarem para essa raiz diretamente, comprimindo o
caminho. A operao retorna o elemento cannico do conjunto.

Figura 6: operao find(x).


Fonte: A Potential-Based Amortized Analysis of the Union-Find Data Structure.

Para uma sequncia mista de


operaes union e find, em elementos, essa
estrutura, com o uso da heurstica de unio por rank, apresenta uma complexidade
amortizada de ( ). Hopcroft e Ulman conseguiram o limite superior de (

) com uso de ambas heursticas. Tarjan, obteve o limite superior atual para o pior-caso,
de ( ( , )) onde ( , ) a inversa da funo de Ackermann [5].

Algoritmo de Kruskal
O algoritmo de Kruskal um algoritmo utilizado na resoluo do problema de
rvores Geradoras Mnimas. Ele ir solucionar o problema, conectando dois vrtices e
de uma floresta, encontrando a prxima aresta de que liga ( , ) com o menor custo.
Esse algoritmo qualificado como guloso, tendo em vista que, a cada passo, ele adiciona
uma nova aresta com o menor peso possvel.
Sua implementao feita atravs do uso de conjuntos-disjuntos, onde cada
conjunto contm os vrtices existentes em uma arvore da floresta atual. Atravs da
operao find(u) = find(v), determinamos se dois ns e , pertencem a mesma arvore,
ou seja, se eles j esto conectados atravs da mesma aresta, em caso negativo, podemos
combinar esses ns atravs da operao union(u, v) [1].

Figura 7: Pseudocdigo para o algoritmo de Kruskal


Fonte: adaptado de Introduction to Algorithms Third Edition.

Na linha 1 temos o conjunto que ir receber as arestas da rvore Geradora


Mnima, inicialmente vazio. Em seguida, criamos uma nova rvore singleton para cada
vrtice a (linhas 2 e 3) atravs da operao MAKE-SET. Na linha 4, ordenamos
todas as arestas de , de maneira no-decrescente de acordo com o peso atribudo a
cada aresta. Logo aps, (linhas 5 8), temos uma iterao, que ir percorrer da primeira
ltima aresta (j ordenadas) de , tal que em cada iterao verificamos se o n e
pertencem a mesma rvore; no pertencendo, eles sero unificados atravs da operao
UNION, incluindo essa aresta ao conjunto A. necessrio realizar essa verificao para
evitar ciclos com a insero de duas ou mais arestas ligando os mesmos vrtices e .
Ao final do lao, teremos inserido todas as arestas necessrias para ligar todos os vrtices

de
aciclicamente com o menor peso possvel, e retornamos o conjunto A, agora
contendo a rvore Geradora Mnima encontrada.

Figura 8: Encontrando A rvore Geradora Mnima atravs do algoritmo de Kruskal.


Fonte:
http://www.professeurs.polymtl.ca/michel.gagnon/Disciplinas/Bac/Grafos/Arvores/ex_exec_kruskal.gif

O tempo de execuo do algoritmo de Kruskal ir depender da maneira como


implementamos a estrutura dos conjuntos-disjuntos. Levando em conta que estamos
utilizando a implementao apresentada anteriormente, utilizando as heursticas de unio
por rank e compresso de caminho e assumindo ainda que o grafo conectado, ou seja,
| | | | 1, o tempo execuo das operaes dessa estrutura de ( ( )).
Levando ainda em considerao que a funo que usaremos para ordenar as arestas na
linha 4 leva ( ). J que (| |) = (lg ) = (lg ), o tempo final do algoritmo
de Kruskal de ( ). Observando que | | < | | , temos que lg| | = (lg ), e
assim podemos representar o tempo do algoritmo como ( lg ) [1].

Esquema de implementao
O algoritmo foi implementado em C++, atravs do framework Visual Studio 2013.
Ele conta com trs classes, a saber: a) Union_Find, pela qual representamos a estrutura
de conjuntos-disjuntos, b) Kruskal, que como o prprio nome sugere, a responsvel pela
execuo do algoritmo de Kruskal e c) Graph, que implementa uma matriz de adjacncia.
O cdigo e outros arquivos necessrios podem ser baixados atravs do seguinte
repositrio: https://www.dropbox.com/s/ef7u2lb3ghyikee/Kruskal.rar?dl=0.
A classe Union_Find foi implementada segundo as orientaes encontradas em
[3]. De incio, essa classe foi construda com duas pequenas diferenas: i) a funo MakeSet inicializava todos os conjuntos com rank 1 e ii) a funo Unite unia dois conjuntos
atravs do seguinte critrio:
if (rank[i] < rank[j]){

// unite by rank.

id[i] = j;
rank[j] += rank[i];
}
else{
id[j] = i;
rank[i] += rank[j];
}

Desse modo, caso o conjunto j tivesse o maior rank, o conjunto i seria atualizado
como seu novo filho, e em seguida, o rank de j seria teria seu valor atual somado com o
valor atual do rank de i. Caso estivssemos tratando da primeira operao de unio, os
ranks de i e j seriam iguais a 1, assim eles cairiam na segunda condio e i receberia j
como seu novo filho e teria seu rank atualizado para 2. Mas como visto em sala de aula,
essa implementao encontra-se incorreta.
A operao Make-set desse modo inicializa o rank de todos os conjuntos com 0 e
a funo Unite foi rescrita da seguinte forma:
if (rank[i] < rank[j]){
id[i] = j;
rank[j] += 1
}
else{
id[j] = i;
rank[i] += 1
}

// unite by rank.

Ficando ento essa classe da forma como foi descrita no paper acima mencionado,
o qual faz parte da bibliografia encontrada em [1].
importante dizer que a estrutura escolhida para armazenar a lista de vrtices foi
a pair, que agrupa pares de valores que podem apresentar diferentes tipos. Esses valores
podem ser acessados individualmente atravs de seus membros pblicos first e second
[4]. Definimos ento o tipo de varivel pii (pair int int) que nada mais do que um pair,
cujo primeiro e segundo membros so inteiros, nele armazenaremos dois vrtices e
simbolizando uma aresta qualquer. Definimos ainda o tipo pip (pair int pair), cujo
primeiro membro um inteiro, onde ser armazenado o valor da aresta e o segundo
membro um pair, do tipo pii.
Para ordenar as arestas de acordo com o seu peso, foi escolhida a funo sort(),
encontrada na biblioteca algorithm. Essa funo ordena os elementos dentro de um
determinado intervalo em ordem ascendente. Em mdia, essa funo tem complexidade
de , onde seria o tamanho desse intervalo [4].
Na implementao do algoritmo por meio de uma matriz de adjacncia, foi usado
um array de inteiros para salvar os vrtices que esto conectados. Quando uma nova
aresta adicionada, esse array atualizado, para conter o novo conjunto de vrtices que
compem a Arvore Geradora Mnima, similar a operao unite dos conjuntos-disjuntos,
assim a operao de unio realizada da seguinte forma:
void Graph::addEdge(int u, int v) {
A[u][v] = A[v][u] = 1;

int pv = parent[v];
int pu = parent[u];

for (int i = 0; i < n; i++)


if (parent[i] == pv)
parent[i] = pu;
}

Dessa forma, o n v sempre inserido como filho do n u, no havendo qualquer


heurstica de aperfeioamento. Essa funo considerada linear e ( ), tendo em vista
que sempre necessrio percorrer todo o array parent. Chegar se um n pertence a um
determinado conjunto feita atravs da seguinte operao:
bool Graph::isReacheble(int u, int v){
return parent[u] == parent[v];
}

Isso pode ser obtido num tempo de (1), assim como a operao find dos
conjuntos-disjuntos.

A ferramenta utilizada para criao dos grafos foi a Standard Network Analysis
Platform (SNAP) 2.3, uma biblioteca de minerao de grafos escrita em C++, capaz de
criar redes massivas de centenas de milhes de ns e bilhes de arestas. Ela consegue
gerar de maneira eficiente grafos randmicos, onde podemos acrescentar diversas
propriedades, tanto nos ns quanto nas arestas [6]. Foram gerados 3 grafos de tamanhos,
100, 500 e 1000 ns, com pesos randmicos nas arestas, com valores entre 0 e 100,
obtidos atravs da funo rand() da biblioteca C++. Assim, o arquivo que contm o grafo
formado apenas por sequncias de dois nmeros, que indicam uma aresta conectando
dois vrtices. Ao ler essa aresta, o programa se encarrega de inserir o seu peso, de forma
dinmica. Optei por esse mtodo para poder testar diferentes escalas de pesos e ver qual
a sua influncia no resultado final.
Abaixo temo os tempos em milissegundos obtidos para ambas implementaes
usando grafos de tamanhos variados:

Quadro 1 Testes para pesos randmicos entre 0 e 100.

Quant. De
ns
100
500
1000

Quant. De
arestas
377
3788
10130

Kruskal com ConjuntosDisjuntos


0,005
0,0345
0,1024

Kruskal com Matriz de


Adjacncia
0,0145
0,06125
0,1726

Fonte: Autoria prpria.

Quadro 2 Testes para pesos randmicos entre 0 e 1000.

Quant. De
ns
100
500
1000

Quant. De
arestas
377
3788
10130

Kruskal com ConjuntosDisjuntos


0,00525
0,0382
0,0975

Kruskal com Matriz de


Adjacncia
0,007
0,0662
0,173

Fonte: Autoria prpria.

Concluso
Como podemos ver, a implementao de Kruskal atravs de conjuntos-disjuntos
apresenta uma considervel melhoria no tempo de execuo. A escala de pesos
randmicos, no entanto, no acrescentou muito nos testes, porm, seria necessrio realizar
diversos outros testes com grafos mais densos, e chegar sua relevncia na tarefa.
Em uma breve busca, podemos encontrar na internet diversas implementaes
para esse algoritmo em diversas linguagens. As quais podemos utilizar como fonte de
estudo para criao do nosso prprio cdigo. O cdigo que apresento nesse trabalho foi
escrito adaptando a perspectiva contida em diversos outros cdigos a minha prpria viso
de como ele deveria funcionar. No meu ponto de vista particular, o algoritmo ficou bem

organizado e bastante legvel tanto para pessoas familiarizadas com c++, quanto aqueles
familiarizados com outras linguagens.
A maior dificuldade que encontrei durante a realizao deste trabalho, foi entender
de forma satisfatria o funcionamento dos conjuntos-disjuntos. Algo que me ajudou de
forma bastante significativa foram os vdeos do professor doutor Robert Sedgewick, da
universidade de Princeton, que apresenta um minicurso sobre essa estrutura, disponveis
livremente atravs do site youtube.
Para finalizar gostaria de dizer que este trabalho foi de grande importncia para
meu crescimento acadmico, tanto no sentido da pesquisa, quanto na aquisio de novos
conhecimentos sobre o estudo de grafos.

Referncias

[1]
Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford.
Introduction to Algorithms Third Edition. 2009 Massachusetts Institute of technology.
[2]
Souza, Kleber J. F. Souza; Guimares, Silvio J. F. Uma Abordagem de
Simplificao de Imagem Colorida Baseada na rvore Geradora Mnima. 2011,
PUC Minas, Belo Horizonte, MG.
[3]
Harfst, Gregory C.; Reingold, Edward M. A Potential-Based Amortized
Analysis of the Union-Find Data Structure. 3 de Agosto de 2000. ACM 2000 Article.
[4] http://www.cplusplus.com/reference.
[5]
Ackermann function.
Disponvel
em
<http://www.saylor.org/site/wpcontent/uploads/2011/06/Ackermann-Function.pdf> Acesso em: 29/03/2015.
[6]

http://snap.stanford.edu/index.html.

Você também pode gostar