Algoritmos para Grafos, via Sedgewick | Índice remissivo
A matriz de adjacência de um digrafo tem colunas e linhas indexadas pelos vértices. Se adj é uma tal matriz então, para cada vértice v e cada vértice w,
As matrizes de adjacência de grafos são simétricas: adj[v][w] = adj[w][v] para todo v e todo w.
(Esta página foi inspirada na seção 17.3 (Adjacency Matrix Representation), em particular nos programas 17.3, 17.4 e 17.5 (p.22-25), do livro de Sedgewick.)
Eis um digrafo e sua matriz de adjacência:
0-1 0-5 1-0 1-5 2-4 3-1 5-3 |
0 1 2 3 4 5
0 0 1 0 0 0 1
1 1 0 0 0 0 1
2 0 0 0 0 1 0
3 0 1 0 0 0 0
4 0 0 0 0 0 0
5 0 0 0 1 0 0
|
Eis um grafo (definido por seu conjunto de arestas) e sua matriz de adjacência:
0-1 0-5 1-5 2-4 3-1 5-3 |
0 1 2 3 4 5
0 0 1 0 0 0 1
1 1 0 0 1 0 1
2 0 0 0 0 1 0
3 0 1 0 0 0 1
4 0 0 1 0 0 0
5 1 1 0 1 0 0
|
Um digrafo será representado por uma struct digraph que contém o número de vértices, o número de arcos e a matriz de adjacência do digrafo.
/* A estrutura digraph representa um digrafo. O campo adj é um ponteiro para a matriz de adjacência do digrafo. O campo V contém o número de vértices e o campo A contém o número de arcos do digrafo. */
struct digraph { int V; int A; int **adj; };/* Um objeto do tipo Digraph contém o endereço de um digraph. */
typedef struct digraph *Digraph;
[O livro de Sedgewick escreve "graph" no lugar do nosso "digraph". Também escreve "E" no lugar do nosso "A".]
Essa mesma estrutura será usada para representar grafos, mas nesse caso escreveremos "graph" e "Graph" no lugar de "digraph" e "Digraph":
#define graph digraph #define Graph Digraph
É apropriado lembrar que, o número de arestas de um grafo é mais significativo que o seu número de arcos. Se G é um Graph, o número de arestas de G é (G->A)/2.
Essas estruturas devem ser consideradas mais como modelos do que como algo definitivo. Elas poderão ser modificadas e adaptadas adiante, conforme as necessidades.
Eis algumas funções básicas de criação e manipulação de digrafos representados por matrizes de adjacência:
/* Esta função devolve (o endereço de) um novo digrafo com vértices 0,..,V-1 e nenhum arco. */
Digraph DIGRAPHinit (int V) { Digraph G = malloc(sizeof *G); G->V = V; G->A = 0; G->adj = MATRIXint(V, V, 0); return G; }/* A função abaixo aloca uma matriz com linhas 0..r-1 e colunas 0..c-1. Cada elemento da matriz recebe valor val. */
int **MATRIXint (int r, int c, int val) { Vertex i, j; int **m = malloc(r * sizeof(int *)); for (i = 0; i < r; i++) m[i] = malloc(c * sizeof(int)); for (i = 0; i < r; i++) for (j = 0; j < c; j++) m[i][j] = val; return m; }/* Esta função insere um arco v-w no digrafo G. Se v == w ou o digrafo já tem arco v-w, a função não faz nada. É claro que v e w não podem ser negativos e devem ser menores que G->V. */
void DIGRAPHinsertA (Digraph G, Vertex v, Vertex w) { if (v != w && G->adj[v][w] == 0) { G->adj[v][w] = 1; G->A++; } }/* Esta função remove do digrafo G o arco que tem ponta inicial v e ponta final w. Se não existe tal arco, a função nada faz. */
void DIGRAPHremoveA (Digraph G, Vertex v, Vertex w) { if (G->adj[v][w] == 1) { G->A--; G->adj[v][w] = 0; } }/* Para cada vértice v do digrafo G, esta função imprime, em uma linha, todos os vértices adjacentes a v. */
void DIGRAPHshow (Digraph G) { Vertex v, w; for (v = 0; v < G->V; v++) { printf("%2d:", v); for (w = 0; w < G->V; w++) if (G->adj[v][w] == 1) printf(" %2d", w); printf("\n"); } }
É claro que essas mesmas funções podem ser usadas para construir grafos. Mas é conveniente adaptar os nomes das funções e escrever uma função específica para inserção de arestas:
#define GRAPHinit DIGRAPHinit #define GRAPHshow DIGRAPHshow/* Esta função insere uma aresta v-w no grafo G. */
void GRAPHinsertE (Graph G, Vertex v, Vertex w) { DIGRAPHinsertA(G, v, w); DIGRAPHinsertA(G, w, v); }
É um bom exercício escrever uma função GRAPHremoveE que remova uma aresta de um grafo.
A maior parte dos exercícios abaixo envolve grafos. Convido o leitor a refazer todos os exercícios depois de trocar "grafo" e "aresta" por "digrafo" e "arco" respectivamente.
A maior parte dos exercícios abaixo envolve grafos. Convido o leitor a refazer todos os exercícios depois de trocar "grafo" e "aresta" por "digrafo" e "arco" respectivamente.
6
0-1
0-5
1-0
1-5
2-4
3-1
Se interpretarmos cada linha do arquivo como uma aresta, podemos dizer que o arquivo define um grafo com vértices 0..V-1. Escreva uma função GRAPHconstruct que receba um arquivo gráfico e construa a matriz de adjacência do grafo. Use as funções GRAPHinit e GRAPHinsertE.