Tiago Madeira

Grafos

Representando Grafos na Programação

No último artigo, conhecemos a representação chamada “grafo” da seguinte maneira:

Grafo desenhado

Como todos sabemos, seria bem difícil trabalhar uma árvore assim na programação! Por isso, existem várias maneiras de representar um grafo. Nesta série só vou usar as duas mais populares:

  • Matriz de Adjacência
  • Lista de Adjacência

Poderíamos falar também sobre a Matriz de Incidência, mas eu nunca precisei utilizá-la, então prefiro só entrar nessas duas mesmo.

Cada vértice é um número

Para representar um grafo, cada vértice sempre vai ser um número. No caso de você querer representar amizade entre duas pessoas, como no exemplo do Orkut no último artigo, você cria um vetor chamado nome[] que contém o nome de cada número…

  1. Eu
  2. João
  3. Maria
  4. José
  5. Pedro

Matriz de Adjacência

A matriz de adjacência é uma matriz de N x N (onde N é o número de vértices do grafo). Ela inicialmente é preenchida toda com 0 e quando há uma relação entre o vértice do x (número da coluna) com o do y (número da linha), matriz[x][y] é marcado um 1.

Vamos escrever este grafo aqui usando uma matriz de adjacência:

Matriz Inicial

  1 2 3 4 5
1
2
3
4
5

Relações do nosso grafo

Já que o grafo não é orientado, a relação 1–2 significa 2–1 também.

  • 1–2 (2–1)
  • 1–3 (3–1)
  • 2–3 (3–2)
  • 2–4 (4–2)
  • 4–5 (5–4)

Essas são as cinco arestas do nosso grafo. Vamos representá-la na matriz de adjacência:

1 2 3 4 5
1 1 1
2 1 1 1
3 1 1
4 1 1
5 1

Simetria

Uma das características da matriz de adjacência quando o grafo não é orientado é a simetria encontrada na “diagonal”. É interessante que se lermos uma coluna de índice v ou uma linha de índice v vamos encontrar a mesma coisa.

Problemas da OBI

Alguns desses programas são complicados, mas isto não entra em questão. Apenas dê uma olhada no recebimento da entrada deles. Todos estão em C. O que eles têm em comum é a utilização de uma matriz de adjacência para guardar o grafo (geralmente nomeada g):

* – Grafo orientado
+ – Grafo ponderado (veremos no próximo artigo)
X – Não queira ver esse problema. Nunca vi solução mais feia. Já estou providenciando uma implementação mais decente… ;)

Descobrir o grau de cada vértice

Eu não disse pra vocês que era fácil conseguir emprego no Orkut? Hehehe… Vamos pensar como podemos descobrir o grau (relembrando… o número de arestas que cada vértice tem OU o número de amigos que cada pessoa tem) na matriz de adjacências. Não basta contar quantos 1s tem na sua linha correspondente? Então façamos isto.

para i \leftarrow{} 1 até N, faça
    grau \leftarrow{} 0
    para j \leftarrow{} 1 até N, faça
        se matriz[i][j] = 1, então
            grau \leftarrow{} grau + 1
        fim-se
    fim-para
    imprima "O vértice " i " tem grau " grau "."
fim-para

O custo é \(\Theta{}(n^{2})\) até no melhor caso… Será que não há uma maneira mais simples de fazer isso? Imagina um negócio do tamanho do Orkut. Milhões de pessoas… Não seria bem mais fácil se ao invés de termos que passar por todos os vértices, só passarmos pelos amigos? Não poderíamos colocar somente seus amigos num vetor? É por isto que utilizamos a lista de adjacência.

Lista de Adjacência

A lista de adjacência consiste em criar um vetor para cada vértice. Este vetor contém cada vértice que o vértice “conhece” (tem uma aresta para). Geralmente é representada com uma matriz, porque cada vértice vai precisar de um vetor diferente, não é? Já que eu não vou ser duas vezes “amigo” de ninguém, então podemos fazer uma matriz de NxN.

  1 2 3 4 5
1          
2          
3          
4          
5          

A lista consiste em escrever para cada número de linha (= vértice) seus amigos, da seguinte maneira:

  1. 2, 3
  2. 1, 3, 4
  3. 1, 2
  4. 2, 5
  5. 4

Portanto, na programação seria representado da seguinte maneira:

  1 2 3 4 5
1 2 3      
2 1 3 4    
3 1 2      
4 2 5      
5 4        

O método da lista de adjacências tem várias vantagens: dependendo de como você implementa você não precisa inicializar a lista (zerar), as buscas são bem mais rápidas (você só passa pelos vértices que são “amigos” do atual) e geralmente você já tem o grau do vértice na ponta da língua (eu, pelo menos, sempre uso um vetor cont que contém o número de amigos de cada vértice para ficar mais fácil inserir o próximo elemento na lista – lista[cont[v]++]=w).

Como implementar

Vamos trabalhar com uma entrada de vários x, y, indicando relação entre x-y (y-x) até que x=0 e y=0. O grafo não é orientado.

Matriz de Adjacências

para i \leftarrow{} 1 até N, faça
    para j \leftarrow{} 1 até N, faça
        matriz[i][j] \leftarrow{} 0
    fim-para
fim-para

enquanto (recebe x, y e x \neq{} 0), faça
    matriz[x][y] \leftarrow{} 1
    matriz[y][x] \leftarrow{} 1
fim-enquanto

Tem vários exemplos implementados em C aqui.

Lista de Adjacências

para i \leftarrow{} 1 até N, faça
    grau[i] \leftarrow{} 0
fim-para

enquanto (recebe x, y e x \neq{} 0), faça
    lista[x][grau[x]++] \leftarrow{} y
    lista[y][grau[y]++] \leftarrow{} x
fim-enquanto

Para quem não programa em C, o variavel++ significa “incrementar variavel depois da instrução atual”.

As duas juntas

para i \leftarrow{} 1 até N, faça
    para j \leftarrow{} 1 até N, faça
        matriz[i][j] \leftarrow{} 0
    fim-para
    grau[i] \leftarrow{} 0
fim-para

enquanto (recebe x, y e x \neq{} 0), faça
    matriz[x][y] \leftarrow{} 1
    matriz[y][x] \leftarrow{} 1
    lista[x][grau[x]++] \leftarrow{} y
    lista[y][grau[y]++] \leftarrow{} x
fim-enquanto

Qual a representação que devo utilizar?

Isso depende totalmente do problema. Em alguns casos, o mais barato é usar as duas representações juntas. As vantagens da lista de adjacências eu já escrevi aqui. A única vantagem da matriz de adjacências é você em tempo constante (não é nem linear) saber se um vértice é amigo de outro. Afinal, basta testar matriz[v][w].

Até maio do ano passado, eu não tinha aprendido isso direito e sempre usava a matriz de adjacências. Por isso muitos dos meus problemas estão resolvidos de forma pouco eficiente… e isso pode ser crucial numa prova. Por isso, saiba usar as duas formas!

Comentários

Peter Jordan

Muito legal seu artigo mas ainda fiquei com algumas lacunas. No final não consegui simular uma rede no orkut com apenas 5 amigos seguindo o seu exemplo. Nos exemplos em C não vi nenhum onde partisse do zero já com as variáveis preenchidas por isso não consegui decifrá-lo. Agradeceria muito se pudesse entrar em contato para que eu pudesse trocar umas informações. Abraço!

Tiago Madeira

Oi Peter! Eu nunca implementei um problema de grafos partindo de um grafo pronto! :S Hehehe… Por isso você não encontrou… =) Mas é o seguinte: Você pode usar ou a matriz de adjacências ou a lista de adjacências. Vamos usar a matriz de adjacências. Ela é a primeira que eu falo no artigo, onde toda relação entre dois caras é representada com um 1 (ex.: João é amigo de Maria).

grafo[João][Maria]=1Onde não tem relação, colocamos 0 (ex.: João e Carlos não se conhecem) grafo[João][Carlos]=0Como implementar isso?Para fazer um grafo pronto de 5x5, você teria que fazer o seguinte (é em C que você programa, né?) int grafo[6][6]; memset(grafo, 0, sizeof(grafo)); //zerando tudo! (apagando as relações) grafo[1][2]=1; //1 é amigo de 2 grafo[2][5]=1; //2 é amigo de 5 // e assim vai Entendeu? Aí depois para contar o grau do vértice (ver quantos amigos tem cada cara) você usa aquele algoritmo que eu proponho logo após o texto “Descobrir o grau de cada vértice. Em C, ficaria assim: ``` for (i=1; i

Espero que dê tudo certo! Qualquer coisa, pode contar comigo.

Um abraço, Tiago. ```

Johnny Everton

o quer dizer problema na OBI em matrizes adjacentes

ilton junior

gostaria de ver um codigo em c de floyd para caminhos d dijktra para custo em lista de adjacencia!!!!

Gean

Sou meio cru em java… estou precisando de fazer uma aplicação que receba os dados do usuário e monte um grafo a partir das entradas, poderiam me dar uma mãozinha ?

Tiago Madeira » Representando Grafos na Programação

[…] O artigo está em outro local agora: Representando grafos na programação […]

Caio Martins

Oi Tiago, gostaria de dar meus parabéns pelo artigo. O engraçado é que eu tava fazendo um grafo orientado achando que era não orientado. tava fazendo: matriz[x][y] = 1; e não: matriz[x][y] = 1; matriz[y][x] = 1; Eu achava que se fizesse isso, eu estaria montando um ciclo. Enfim, eu gostaria de dar uma sugestão: Acho que seria interessante colocar implementações dinâmicas além de encadeadas. Abração Boas festas

Ricardo

Olá, tudo bem? Estou apanhando um pouco em escrever uma classe em java que produza a seguinte solicitação: 1. Construa uma classe Java que armazene um grafo através da representação por matriz de adjacência. Implemente um método que permita a leitura de um grafo armazenado em um arquivo texto. Construa outro método para armazenar em um arquivo um grafo armazenado na memória. Grafo a = new Grafo(); a.carregar(“arquivo.txt”); // Carrega o grafo do disco. … a.salvar(“arquivo.txt”); // Armazena o grafo no disco.

Ricardo

O amigo poderia me auxiliar nessa tarefa? Cordiais saudações, Ricardo

brigida

vc colocou varios exemplos implementados de matrizes de adjacencias teria como colocar tambem com listas?!

Tiago Madeira

Logo embaixo das matrizes de adjacência há um título bem grande “Lista de adjacências” que explica e implementa listas. ;)

Tiago Madeira

Ricardo, É preciso saber como o grafo está representado no arquivo que o Java lê (como é o formato da entrada) para resolver este problema.

Felippe

Olá Tiago, seria possível você descrever pelo menos uns 2 exemplos reais de grafos (não direcionados se possível) como o exemplo do orkut, digo em relação a teoria mesmo, como no seu post. Parabéns pelos artigos. Um abraço.

Adriano

Fera, uma matriz de adjacências caracteriza unicamente um grafo, porem a um mesmo grafo G podem corresponder varias matrizes diferentes?Porque? Abraço, Adriano.

Claudio

eu gostaria de saber este algoritmo: faça um algoritmo que determine, para um digrafo, a quantidade de vertice que não possuem aresta saindo, considere que são fornecida as matrizes de incidencia e adjacencia do digrafo. entrada : matriz de incidencia MI[20,30] matriz de adjacencia - MA[20,20] saida quantidade de vertice - QV 2) um algoritmo que determina quais vertices são adjacentes a todos os vertices de um digrafo, considere que são fornecidas as matrizes de incidencia e adjacencia do grafo. entrada matriz incidencia - MI[20,30} matriz adjacencia - MA[20,20] vertice de origem - VO saida vetor de vertice - VVI[20]

plvr ybncof

pksgtlvwd rauskizvj ebky shjmgoqy nyxlqvbwm sjuexr wote

MASLIVAK

Olá, primeiramente gostaria de parabenisa-lo pelos seus artigos, são muito bons. Estou fazendo um trabalho de AA e preciso de uma dica sobre as diferenças básicas sobre a análise de algoritmos em grafos e os outros algoritmos (como de buscas heap, quick, etc…). Abraco.

Michelli

Estou tentando baixar as implementações de Carga Pesada e Orkut e não estou conseguindo. Teria como mandar para meu e-mail?

Renato

Hiiii aii meu Brother .. preciso de auxilio no algoritmo, de Dijkstra ..

Si

poderia falar sobre matriz de incidêdencia qual as suas diferenças???

Cesar

Olá Tiago, Teus links com os exemplos em C estão quebrados! Voce pode arrumar?

Tiago Madeira

Arrumados (quase 7 anos depois) :)

camila

Oi tiago, adorei o site mas infelizmente os exemplos que voce deixou em c estao com os links todos quebrados….tem como disponibilizar nao?? estou em duvida como implementar e isso iria me ajudar muito!! att , camila

rodolfo

Oi tiago, adorei o site mas infelizmente os exemplos que voce deixou em c estao com os links todos quebrados….tem como disponibilizar nao?? estou em duvida como implementar e isso iria me ajudar muito!! att Rodolfo

Daniel

Tiago Parabéns pelao artigo. Por gentileza poderia enviar o codigo fonte do exercicio ambulância.c (problemas da OBI) no qual tem aplicações prática do conceito de matriz de adjacência ? por gentileza envie para o e-mail danielbrv@hotmail.com Obrigado por enquanto.

Rafael

Por gentileza poderia enviar o codigo fonte do exercicio ambulância.c (problemas da OBI) no qual tem aplicações prática do conceito de matriz de adjacência ? to com complicações nesse exercicio. por gentileza envie para o e-mail, mencionado. agradeço

alynne raquel

Boa noite, gostei muito do seus posts. estou precisando de sua ajuda e espero que você possa e ajudar, você tem algum algoritmo implementado em pascal, delphi ou portugol que me diga se a matriz de adjacencia tem caminho ou para testar se tem articulação, qualquer uma das duas opções já salva minha vida =D obrigada!

Elvis Luis Zamian delgado

Cara será que voce pode me ajudar, eu preciso fazer um algoritmo que calcule o melhor caminho( menor custo) entre as cidades, são dez cidades cadastradas, e caso tenha caminho tem um certo valor, se não tem o valor é -1 e se é de cidade para mesma cidade grau =o. Eu fiz a matriz 10x10, coloquei os valores e escrevi a matriz[i][j], so que agora não consigo fazer mais nada, pq se a pessoa sair por exemplo de são paulo matriz[1][1] e for para sorocaba matriz [6][6] tenho que percorrer todos os caminhos e ver o melhor, como faço?

Junior

Tiago estou desenvolvendo um projeto em ‘C’, tenho um labirinto e preciso implementar ou mais algoritmos que encontrem a saída mas nem sei por onde começar, podia me ajudar ?

Duano

Olá, Embora este assunto tenha iniciado há algum tempo, eu enfrento hoje um problema que julgo que já exista uma solução. Todas as abordagens que vi foram para construir a matriz de adjacência. Contudo, um desafio que preciso ultrapassar é escrever um código capaz de simular o desenho de um grafo. E também o contrario (um código para passar da matriz ao grafo). Como sabem as redes podem ter muitos Nós e não é simples realizar esta tarefa à mão. Eu estou a pensar em ter um ficheiro de entrada do género uma lista de listas aonde terei os vários vértices e também a informação de quais vértices estão ligados. Mas aqui existe a questão de como será este ficheiro (eu tenho que construir para um grafo com um nº N de vértices). Alguém consegue me ajudar?

Karen Gianne

Olá, não consigo abrir seus exemplos, dando 404 Not Found aqui! rs

Tiago Madeira

Encontrei esses velhos códigos no servidor e arrumei os links :)

Marcella

Você poderia atualizar os links? Não consigo entrar neles.

Marcella

Você poderia atualizar os links? Não consigo entrar neles.

Tiago Madeira

Desculpe. Vou atualizar assim que puder.

Bruna Bueno

Ótima explicação, ainda ajuda em 2017 :D

Feminino

Bom dia! tenho um trabalho no qual devo implementar um grafo com uma interface gráfica utilizando o matlab. estou tendo muitas dificuldades, consigo implementar o grafo em C facilmente, mas estou apanhando no matlab. Agradeceria muito se pudesse me ajudar. Obrigada.

Obrigado! Seu comentário foi enviado e será publicado quando for aprovado.

Infelizmente ocorreu um erro ao enviar seu comentário.