150 likes | 274 Views
Estruturas de Dados (Grafos). Ronaldo Celso Messias Correia. Busca em Grafos. Dado um grafo G = (V, A) e um vértice v pertencente a V, deseja-se encontrar todos os vértices em G que estão conectados a v. Ou, dado um grafo G = (V, A), deseja-se visitar todos os vértices de G.
E N D
Estruturas de Dados (Grafos) Ronaldo Celso Messias Correia Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Busca em Grafos • Dado um grafo G = (V, A) e um vértice v pertencente a V, deseja-se encontrar todos os vértices em G que estão conectados a v. • Ou, dado um grafo G = (V, A), deseja-se visitar todos os vértices de G. • Serão vistas duas maneiras de realizar essas tarefas: • Busca em profundidade, e; • Busca em largura. Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Busca em Profundidade • A busca em profundidade (depth-first search) é um algoritmo para caminhar no grafo. • A estratégia é buscar o vértice mais profundo no grafo sempre que possível. • As arestas são exploradas a partir do vértice v mais recentemente descoberto que ainda possui arestas não exploradas saindo dele. • Quando todas as arestas adjacentes a v tiverem sido exploradas a busca anda para trás (backtrack) para explorar vértices que saem do vértice do qual v foi descoberto. • O algoritmo é a base para muitos outros algoritmos importantes, tais como verificação de grafos acíclicos, ordenação topológica e componentes fortemente conectados. Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Versão recursiva do algoritmo procedimento Busca(G: Grafo) Para cada vértice v de G: Marque v como não visitado Para cada vértice v de G: Se v não foi visitado: Busca-Prof(v) procedimento Busca-Prof(v: vértice) Marque v como visitado Para cada vértice w adjacente a v: Se w não foi visitado: Busca-Prof(w) Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Versão recursiva do algoritmo /* Supondo que os FLAGs dos vertices sejam todos iguais a 0 */ void busca_profund(heads *G,int i) {no *aux;G[i].FLAG = 1;for (aux=G[i].ADJ;aux;aux = aux->NEXT) if (G[aux->VERTEX].FLAG == 0) busca_profund(G,aux->VERTEX)} Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
5 1 3 2 4 7 6 8 Execução do algoritmo Busca-Prof(1) Busca-Prof(2) Busca-Prof(4) Busca-Prof(5) Busca-Prof(3) Busca-Prof(6) Busca-Prof(7) Busca-Prof(8) Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Busca em Largura • A busca em largura (breadth-first search) expande a fronteira entre vértices descobertos e não descobertos uniformemente através da largura da fronteira. • O algoritmo descobre todos os vértices a um distância k do vértice origem antes de descobrir qualquer vértice a uma distância k+1. • O grafo pode ser direcionado ou não direcionado Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Algoritmo de busca em Largura procedimento Busca-Largura(v: vértice) Inicializar F Marcar v como visitado Inserir v no final de F Enquanto F não vazio: u := primeiro elemento de F Retirar u de F Para cada vértice w adjacente a u: Se w não foi visitado: Marcar w como visitado Colocar w no final de F procedimento Busca(G: Grafo) Para cada vértice v de G: Marcar v como não visitado Para cada vértice v de G: Se v não foi visitado: Busca-Largura(v) Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Algoritmo de busca em Largura /* Suponha Q uma fila de numeros inteiros e os FLAGs dos vertices sejam todos iguais a 0 */void Busca_Largura(heads *G) {int i; no *aux; G[0].FLAG = 1; INSERE(Q,0); while (EMPTY(Q) != 1) { i = REMOVE(Q); /* Retira um elemento da fila */ for (aux = G[i].ADJ; aux; aux = aux->NEXT) { if (G[aux->VERTEX].FLAG == 0) { G[aux->VERTEX].FLAG = 1; INSERE(Q,aux->VERTEX); } } } } Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
5 1 3 2 4 7 6 8 Execução do algoritmo Busca-Larg(1) Busca-Larg(2) Busca-Larg(3) Busca-Larg(5) Busca_Larg(4) Busca-Larg(6) Busca-Larg(7) Busca-Larg(8) Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Teste para verificar se grafo é Acíclico • A busca em profundidade pode ser usada para verificar se um grafo é acíclico ou contém um ou mais ciclos. • Se uma aresta de retorno é encontrada durante a busca em profundidade em G, então o grafo tem ciclo. • O algoritmo de busca em profundidade pode ser modificado para detectar ciclos em grafos orientados simplesmente verificando se um vértice w adjacente a v possui o FLAG=1 na primeira vez que a aresta (v, w) é percorrida. Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Caminho mais curto • Quando todas as arestas de grafo G possuem peso 1, o problema de encontrar o caminho de menor custo entre um vértice s e os outros vértices de G, se resume ao caminho mais curto entre s e os outros vértices do grafo G, ou seja, o caminho com o menor número de arestas Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Caminho mais curto O caminho mais curto de s até o próprio vértice v3 é 0. Os vértices que estão a uma distância 1 de s , v1 e v6. Os vértices que estão a uma distância 2 de s podem ser encontrados através dos vértices adjacentes aos vértices v1 e v6, cujo caminho mais curto ainda não tenha sido encontrado. Na figura acima estes vértices são v2 e v4. Seguindo o procedimento acima, podemos encontrar os vértices que estão a uma distância 3,4 etc. Note que o esquema acima é muito parecido com o método de busca em largura. Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Algoritmo de caminho mais curto void calc_dist(heads *G, int s) /* s eh o indice do vertice fonte */ {int i;no *aux;for(i=0; i<NUMVERT; i++){ G[i].FLAG = 0; G[i].DIST = MAXINT; /* MAXINT eh o maior inteiro representavel */}G[s].FLAG = 1;G[s].DIST = 0;INSERE(Q,s);while (EMPTY(Q) != 1){ i = REMOVE(Q); for(aux = G[i].ADJ; aux; aux = aux->NEXT) { if (G[aux->VERTEX].FLAG == 0) { G[aux->VERTEX].FLAG = 1; G[aux->VERTEX].DIST = G[i].DIST + 1; INSERE(Q,aux->VERTEX); } } } } Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br
Caminho de Custo Mínimo - Dijkstra • O algoritmo de Dijkstra é o mais famoso dos algoritmos para cálculo de caminho de custo mínimo entre vértices de um grafo e, na prática, o mais empregado. • Escolhido um vértice como raiz da busca, esse algoritmo calcula o custo mínimo deste vértice para todos os demais vértices do grafo. • O algoritmo pode ser usado sobre grafos orientados (dígrafos), ou não, e admite que todas as arestas possuam pesos não negativos (nulo é possível). Esta restrição é perfeitamente possível no contexto de redes de transportes, onde as arestas representam normalmente distâncias ou tempos médios de percurso; poderão existir, no entanto, aplicações que as arestas apresentam pesos negativos, nestes casos o algoritmo não funcionará corretamente. Ronaldo Celso Messias Correia – ronaldo@fct.unesp.br