jueves, 14 de julio de 2011

ANSI C tarea: Depth First Search

DFS (en inglés Depth First Search) es un algoritmo que nos sirve para movernos a través de la estructura de un grafo. Básicamente permite visitar los vértices de un grafo, pero existen muchos algoritmos que están basados en DFS para realizar sus distintas funcionalidades. Su principio de funcionamiento es bastante sencillo: hay que avanzar en profundidad visitando cada nodo mientras sea posible visitarlo, si no es posible visitar a un nodo, entonces se realiza un procedimiento llamado "backtracking", en el cual comenzamos a regresar por el camino donde llegamos.

Para saber si un vértice es "visitable", contiene tres colores que funcionan como identificadores de su estado:

1. Blanco: Significa que el vértice no ha sido visitado.

2. Gris: La visita a ese vértice está en progreso.

3. Negro: Ya se terminó la exploración de ese nodo y se dice que está visitado.

También se pueden tomar sólo dos colores o los valores verdadero y falso para determinar el estado de un nodo.

Inicialmente, todos los vértices son coloreados de blanco y conforme avanza la búsqueda o visita, sus colores van cambiando para representar su estado.

En esta ocasión deseaba mostrar un ejemplo de esta implementación, sin embargo, no logré mi objetivo pero de todas formas quiero dejar el código visto en clase para representar un grafo junto con las modificaciones que comencé a hacerle para intentar producir un DFS.

Este es el código del archivo grafo.c en donde se encuentran las funciones esArista y DFS que comencé a construir:

#include <stdio.h>
#include <stdlib.h>
#include "bool.h"

typedef struct algo {
  char caracter;
  int id;
  struct algo* sig;
  //Estado del nodo: 'b' = blanco, no visitado,
  //'g' = gris, visitado, 'n' = negro, ya no tiene aristas por visitar
  char estado;
} lista;

int etiqueta(lista** nombres, char a, 
      int* sigId) {
  lista* l = *nombres;
  lista* nuevo = NULL;
  int n = *sigId;
  if (l == NULL) { // no hay nada
    nuevo = (lista*)malloc(sizeof(lista));
    nuevo->caracter = a;
    nuevo->id = n++;
    *sigId = n;
    nuevo->estado = 'b';
    nuevo->sig = NULL;
    *nombres = nuevo;
    return nuevo->id;
  }
  while (1) { // mientras siempre
    if (l->caracter == a) {
      return l->id; // ya esta
    }
    if (l->sig != NULL) {
      l = l->sig; // avanzar en la lista
    } else { // lo ponemos al final
      nuevo = (lista*)malloc(sizeof(lista));
      nuevo->caracter = a;
      nuevo->id = n++;
      *sigId = n;
      nuevo->estado = 'b';
      nuevo->sig = NULL;
      l->sig = nuevo; // ligar en la lista
      return nuevo->id;
    }
  }
}

char recuperar(lista* l, int a) {
  while (l != NULL) { // mientras siempre
    if (l->id == a) {
      return l->caracter;
    }
    if (l->sig != NULL) {
      l = l->sig; // avanzar en la lista
    }
  }
  return '?';
}

//este es un metodo que intente construir para verificar que 
//hay una arista entre dos nodos dados
bool esArista(int** matriz, int a, int b){
  return(matriz[a][b] == 1);
}

//este es el metodo que intente construir para realizar un DFS
void DFS(lista** lista, int** matriz){
  lista* listaDFS = *lista;
  lista* aux = *lista;
  listaDFS -> estado = 'g';
  while(aux != NULL){
    if(esArista(matriz, listaDFS->id, aux->id) && 
       aux->estado == 'b'){
      print("%d\n", listaDFS->id);
      DFS(aux->siguiente, matriz);
    }
  }
  listaDFS->estado = 'n';
}

int main(int argc, char** args) {
  char* archivo = NULL;
  char* segundo = NULL;
  FILE* entrada = NULL;
  FILE* salida = NULL;
  lista* nombres = NULL;
  lista* aux = NULL;
  char a, b;
  int na, nb, i, j, n = 0;
  int** matriz = NULL;
  bool sinSalida = FALSE;

  if (argc < 3) {
    printf("Ponme los archivos guey.\n");
    return 0;
  }
  archivo = args[1];
  segundo = args[2];
  entrada = fopen(archivo, "r"); // r = lectura
  if (entrada == NULL) {
    printf("No se pudo con %s.\n", archivo);
    return 0;
  }
  salida = fopen(segundo, "w+"); // escribe o crea
  if (salida == NULL) {
    sinSalida = TRUE;
    printf("No habra salida.\n");
  }
  while (!feof(entrada)) {
    fscanf(entrada, "%c %c\n", &a, &b);
    na = etiqueta(&nombres, a, &n);
    nb = etiqueta(&nombres, b, &n);
    printf("Recuperado: (%c=%d, %c=%d).\n", 
    a, na, b, nb);
  }
  printf("Fueron en total %d nodos.\n", n);
  matriz = (int**)malloc(sizeof(int*)*n);
  for (i = 0; i < n; i++) {
    matriz[i] = (int*)malloc(sizeof(int)*n);
    for (j = 0; j < n; j++) {
      matriz[i][j] = 0; // no hay conexion
    }
  }
  rewind(entrada);
  while (!feof(entrada)) {
    fscanf(entrada, "%c %c\n", &a, &b);
    na = etiqueta(&nombres, a, &n);
    nb = etiqueta(&nombres, b, &n);
    // hay arista (na, nb) = (nb, na)
    matriz[na][nb] = 1;
    matriz[nb][na] = 1;
  }
  fclose(entrada);
  if (salida == NULL) {
    salida = stdout;
  }
  fprintf(salida, "    ");
  for (j = 0; j < n; j++) {
    fprintf(salida, "%c ", recuperar(nombres, j));
  }
  fprintf(salida, "\n   ");
  for (j = 0; j < n; j++) {
    fprintf(salida, "--", recuperar(nombres, j));
  }
  fprintf(salida, "\n");
  for (i = 0; i < n; i++) {
    fprintf(salida, 
     "%c | ", recuperar(nombres, i));
    for (j = 0; j < n; j++) {
      fprintf(salida, "%d ", matriz[i][j]);
    }
    fprintf(salida, "\n");
  }
  if (!sinSalida) {
    fclose(salida); // cerrar archivo
  }

  DFS(&nombres, matriz);

  // borrar la lista (una vez que ya no se ocupa)
  while (nombres != NULL) {
    aux = nombres->sig;
    free(nombres);
    nombres = aux;
  }

  for (i = 0; i < n; i++) {
    free(matriz[i]);
  }
  free(matriz);
  return 1;
}

Al compilar lo codificado, estos son los errores que aparecen:

Referencias

Algorithms and Data Structures with implementations in Java and C++. En http://www.algolist.net/Algorithms/Graph/Undirected/Depth-first_search. Visitado el 14 de Julio de 2011.

1 comentario:

  1. Imagino que son los espacios en "listaDFS -> estado = 'g';" que lo rompen. Avísame al haberlo corregido para volver a checar. Tal cual la tarea vale 7.

    ResponderEliminar