Revistas en disco
 Fanzine Nº3 - Enero 1993
Anterior
Menú
Logotipo

Fanzine 3
ÉPOCA II. ENERO 1993

TÉCNICAS DE INTELIGENCIA ARTIFICIAL: ESTRUCTURAS DE DATOS

© Warlord

Hoy trataremos un tema muy interesante y de enorme aplicación práctica como son las estructuras de datos. En particular hablaré de las listas y de los árboles binarios.


LISTAS DOBLEMENTE ENLAZADAS:

Como ya sabréis, una lista es un conjunto de datos almacenados sencuencialmente ... es decir, algo así:

 ----     ----
|    |->-|    |->- ......
 ----     ----

En cada nodo podemos guardar toda la información que queramos (nombre, teléfono, dirección ...). Es decir, básicamente en cada nodo de la lista podemos guardar dos campos: Uno que sea el que guarda la información propiamente dicha y otro que sea un puntero a la dirección del siguiente elemento de la lista. Sin embargo a veces resulta útil utilizar otro puntero que apunte al elemento ANTERIOR en la lista, pues en caso de perder accidentalmente la información de uno de ellos, podemos utilizar el otro para reconstruir la lista. Es el caso de las listas doblemente enlazadas.

Como creo que esta estructura es bastante fácil de entender, me limitaré a dar el source de rigor ...

 /*Warlord, Julio 1988*/
 struct direc {
  char nombre[40]; /*ejemplo de campo info*/
  char calle[40];
  char ciudad[20];
  struct direc *sig;
  struct direc *ante;
 }info;
 /* crear una lista doblemente enlazada. Se devuelve un puntero al primer
    elemento, dado que es posible que se inserte un nuevo elemento al
    principio de la lista*/
 struct direc *dl_insert(i,top) /*almacenamiento ordenado*/
 struct direc *i; /*nuevo elemento*/
 struct direc *top; /*comienzo de la lista*/
 {
  struct direc *ant,*p;
  if (ultimo=NULL){
   i->sig=NULL;
   i->ante=NULL;
   ultimo=i;
   return i;
  }
 p=top /*principio de la lista*/
 ant=NULL;
 while(p){
   if(strcmp(p->nombre,i->nombre)<0){
     ant=p;
     p=p->sig;
   }
   else{
     if(p->ante){
       p->ante->sig=i;
       i->sig=p;
       i->ante=p->ante;
       p->ante=i;
       return top;
     }
     i->sig=p; /*nuevo primer elemento*/
     i->ante=NULL;
     p->ante=i;
     return i;
   }
 }
 ant->sig=i; /*ponerlo en el final*/
 i->sig=NULL;
 i->ante=ant;
 ultimo=i;
 return ppio;
 } 


ÁRBOLES BINARIOS:

¿Qué es un árbol binario?... bueno, creo que su nombre lo dice todo: Es una estructura binaria en forma de árbol. Esto es:

           -----
          |     |  <------ NODO RAIZ
          /-----\
         /       \
        /         \
      -----       -----
     |     |     |     | <----------PRIMER NIVEL
     /-----\      -----\
    /       \           \
 -----     -----       -----
|     |   |     |     |     | <-----SEGUNDO NIVEL
 -----     -----       -----        (NODOS TERMINALES) 

Este ejemplo es un árbol muy sencillito. Tiene sólo dos niveles. 2 nodos en el primer nivel y 3 en el segundo. Creo que ya lo habréis entendido.Un árbol binario es una estructura que comienza con un nodo(llamado "raíz" del árbol) y a partir del cual se derivan otros nodos secundarios (las ramas del árbol)

Generalmente, cada nodo tiene dos ramas, una izquierda y otra deracha, aunque puede tener todas las que queramos.

La inmensa mayoría de la inmensa minoría que esté leyendo este artículo pensará ... ¿y a mí esto para qué me sirve?. Veamos, hay muchas estructuras en la práctica que son en forma de árbol. Por ejemplo, los directorios forman estructura de árbol:

     - C 
DF0: - DEVS   .system configuration 
              -PRINTERS
                               .epsonx 
     - S     .startup-sequence 
     - SOURCES 

Supongamos que queremos hacer un comando que busque un determinado archivo en nuestro directorio. Si tenemos 3 o 4 directorios es fácil. ¿Pero y si tenemos cientos?.

Volviendo al tema de los juegos de estrategia, supongamos que tenemos 20 países, cada país está dividido en 10 provincias y en cada provincia hay 3 ciudades. ¿Cómo manejamos esta información?. Fácilmente si la estructuramos como un árbol ...

                     NODO RAIZ 
                    /  | | | \ \  \
             PAIS 1 ...........    PAIS 20 
           /  |  | \              / | | \
    PROV.1 ... PROV.5  ..........
    / | \
CID.1 ...CID.3  ....... 

¿Está claro, no?

Po vale. Po bueno. Po ahora vamos a ver como buscar en un árbol.Hay 3 formas de buscar:

A) IZQDA-RAIZ-DERECHA
B) RAIZ-IZQDA-DERECHA
C) IZQDA-DERECHA-RAIZ 

Esto no es tan fácil como parece y de hecho es muy difícil de explicar. Os pondré un ejemplo de árbol:

     a     El árbol se recorre así en cada caso:
   /   \
  b     e  A) cbdafeg
 /\    /\  B) abcdefg
c  d  f  g C) cdbfgea

Si no lo entendéis no calentaros demasiado la cabeza. Es igual en los tres casos. Podéis inventaros otras formas de recorrerlo según se adapte a las necesidades del programa. En cualquier caso, las tres anteriores son las mejores.

En cada nodo del árbol, hay que guardar varios campos:

  1. Información: Es decir, el nombre de la ciudad o provincia en el caso del juego, el nombre del directorio o fichero ...
  2. Un puntero hacia el nodo derecho
  3. Otro hacia el nodo izquierdo

Si el árbol tuviera más de dos ramas por nodo, habría que guardar tantos campos como ramas.

Y como siempre, os incluyo un pequeño source que imprime un árbol por el método A. Es simplemente como muestra para aquellos que les interese. ¡Ah!, aquí también aparecen las funciones recursivas que he comentado en otro artículo. Bueno, esto es todo. Os dejo con el programita ...

¡Hasta otra amigos!

 /*Arboles binarios*/
 /*Warlord Noviembre 1992*/
 #include <malloc.h>
 #include <stdio.h>
 struct arb {
   char info;
   struct arb *izq;
   struct arb *der;
   }
 sbstruct arb *raiz; /* primer nodo en el árbol*/
 void imprime_arbol(); 
 main() /*programa que imprime el arbol*/
 {
  char s[80];
  struct arb *arbol();
  raiz=NULL; /*inicializacion de la raiz*/
  do {
   printf("introduzca una letra; ");
   gets(s);
   if(!raiz) raiz=arbol(raiz,raiz,*s);
   else arbol (raiz,raiz,*s);
  } while (*s);
  imprime_arbol(raiz,0);
 } 
 struct arb *arbol(raiz,r,info)
 struct arb *raiz;
 struct arb *r;
 char info;
 {
  if(!r) {
   r=(struct arb *) malloc(sizeof(struct arb));
   if(!r) {
    printf("no hay memoria\n");
    exit(0);
   }
   r->izq=NULL;
   r->der=NULL;
   r->info=info;
   if(!raiz) return r; /*primera entrada*/
   if(info<raiz->info) raiz->izq=r;
   else raiz->der=r;
   return r;
  }
  if(info<r->info) arbol(r,r->izq,info);
  else
  if(info>r->info) arbol(r,r->der,info);
 } 
 void imprime_arbol(r,l)
 struct arb *r;
 int l;
 {
  int i;
  if(!r) return;
  imprime_arbol(r->izq,l+1);
  for(i=0;i<l;++i) printf("    ");
  printf("%c \n",r->info);
 imprime_arbol(r->der,l+1);
 }

Envía esta página web a un amigo:
Esta opción está desactivada temporalmente, rogamos disculpen las molestias

Volver a la página anterior

Al menú principal