Busca em largura

Este capítulo discute uma implementação clássica do algoritmo genérico de busca. Nessa implementação, o conjunto de vértices ativos é administrado como uma fila (= queue), ou seja, cada iteração escolhe o vértice ativo que foi marcado há mais tempo. O resultado dessa política é conhecido como busca em largura (= breadth-first searchBFS).

Dado que o conjunto de vértices ativos é tratado como uma fila, podemos lidar, de uma só vez, com todos os arcos que saem de v e assim dispensar o conjunto A(v). O algoritmo genérico de busca pode ser reformulado assim:

enquanto a fila não está vazia faça

seja v o primeiro vértice da fila

para cada vértice w adjacente a v faça

se w não está marcado

então marque w

então insira w no final da fila

retire v da fila

Implementação

Eis a implementação do algoritmo em C, usando as estruturas de dados do SGB:

#define marca x.I

#define prox y.V

void busca_em_largura (Graph *g, Vertex *r) {

Vertex *v, *w, *ativo, *ultimoArc *a;

for (v = gvertices; v < gvertices + gn; v++)

vmarca = 0;

rmarca = 1;

ativo = ultimo = rultimoprox = NULL;

while (ativoNULL) {

v = ativo;

for (a = varcs; aNULL; a = anext) {

w = atip;

if (wmarca ≡ 0) {

wmarca = 1;

wprox = NULL;

ultimoprox = w;

ultimo = w;

}

}

ativo = ativoprox;

}

}

A função recebe um grafo g e um vértice r e marca o território de r. Um vértice v é considerado marcado se vmarca vale 1. A fila de vértices ativos é

ativo, ativoprox, ativoproxprox, .… , ultimo, NULL.

Versão com predecessores

É fácil escrever uma versão com predecessores no lugar das marcas:

#define pred x.V

#define prox y.V

void busca_em_largura (Graph *g, Vertex *r) {

Vertex *v, *w, *ativo, *ultimo;  Arc *a;

for (v = gvertices; v < gvertices + gn; v++)

vpred = NULL;

rpred = r;

ativo = ultimo = rultimoprox = NULL;

while (ativoNULL) {

v = ativo;

for (a = varcs; aNULL; a = anext) {

w = atip;

if (wpredNULL) {

wpred = v;

wprox = NULL;

ultimoprox = w;

ultimo = w;

}

}

ativo = ativoprox;

}

}

Exercícios 1

  1. Que acontece se inserirmos ativo = ativoprox logo depois da linha v = ativo no código da função busca_em_largura?
  2. O que há de errado com o seguinte código de busca? Ele marca corretamente o território de r? Dê um pequeno grafo que derrube o código.

    for (v = gvertices; v < gvertices + gn; v++)

    vmarca = 0, vprox = NULL;

    ativo = ultimo = r;

    while (ativoNULL) {

    v = ativo;

    vmarca = 1;

    for (a = varcs; aNULL; a = anext) {

    w = atip;

    if (wmarca ≡ 0) {

    ultimoprox = w;

    ultimo = w;  }  }

    ativo = ativoprox;  }

  3. Escreva uma variante da função busca_em_largura que receba um grafo e um vértice r e imprima, uma e uma só vez, o nome (campo name) de cada vértice do território de r.
  4. Escreva uma variante da função busca_em_largura que marque os vértices do terrítório de r com 1, 2, 3, etc. à medida que os vértices forem sendo encontrados.
  5. Escreva uma versão recursiva da função busca_em_largura.
  6. Analise e discuta a seguinte função:

    #define marca x.I

    #define prox y.V

    void busca (Graph *g, Vertex *r) {

    Vertex *v, *w, *ativo;  Arc *a;

    for (v = gvertices; v < gvertices + gn; v++)

    vmarca = 0;

    rmarca = 1;

    ativo = rativoprox = NULL;

    while (ativoNULL) {

    v = ativo;

    ativo = ativoprox;  /* 9 */

    for (a = varcs; aNULL; a = anext) {

    w = atip;

    if (wmarca ≡ 0) {

    wmarca = 1;

    wprox = ativo;

    ativo = w;

    }

    }  /* 17 */

    }  /* 18 */

    }

    A função marca corretamente o território de r? O conjunto de vértices ativos parece ser administrado como uma pilha; isso é de fato verdade? Que acontece se a linha 9 for colocada entre as linhas 17 e 18?