Вы находитесь на странице: 1из 30

Introduccin a la estructuras de datos

Introduccin a Listas Enlazadas


Definicin
Las listas enlazadas son estructuras de datos semejantes a los array salvo que el
acceso a un elemento no se hace mediante un ndice sino mediante un puntero.
La asignacin de memoria es hecha durante la ejecucin. En una lista los
elementos son contiguos en lo que concierne al enlazado.

Construccin del modelo de un elemento de la lista


Para establecer un elemento de la lista, ser utilizado el tipo struct. El elemento de
la lista tendr un campo dato y un puntero siguiente. El puntero siguiente tiene que
ser del mismo tipo que el elemento, si no, no podr apuntar hacia el elemento. El
puntero siguiente permitir el acceso al prximo elemento
typedef struct ElementoLista {
char
*dato;
struct ElementoLista *siguiente
}Elemento;

Para tener el control de la lista es preferible guardar determinados elementos: el


primer elemento, el ltimo elemento, el nmero de elementos. Para ello ser
empleado otra estructura (no es obligatorio, pueden ser utilizadas variables).
typedef struct ListaIdentificar {
Elemento *inicio;
Elemento *fin;
int tamao;
}Lista;

Operaciones sobre las listas enlazadas


Para la insercin y la eliminacin, una nica funcin bastar si est bien concebida
de acuerdo a lo que se necesite. Debo recordar que este artculo es puramente
didctico. Por lo tanto, he escrito una funcin para cada operacin de insercin y
eliminacin.

Inicializacin
void inicializacion (Lista *lista);
Modelo de la funcin:
void inicializacion (Lista *lista){
lista->inicio = NULL; lista->fin = NULL; tamao = 0;}
Insercin de un elemento en la lista
Insercin y el registro de los elementos: declaracin del elemento que se va a
insertar, asignacin de la memoria para el nuevo elemento, llena el contenido del
campo de datos, actualizacin de los punteros hacia el primer y ltimo elemento si
es necesario. Caso particular: en una lista con un nico elemento, el primero es al
mismo tiempo el ltimo. Actualizar el tamao de la lista Para aadir un elemento a
la lista se presentan varios casos: la insercin en una lista vaca, la insercin al
inicio de la lista, la insercin al final de la lista y la insercin en otra parte de la
lista.

Insercin en una lista vaca


Ejemplo de la funcin:
int ins_en_lista_vacia (Lista *lista, char *dato);

La funcin retorna 1 en caso de error, si no devuelve 0.


Las etapas son asignar memoria para el nuevo elemento, completa el campo de
datos de ese nuevo elemento, el puntero siguiente de este nuevo elemento
apuntar hacia NULL (ya que la insercin es realizada en una lista vaca, se utiliza
la direccin del puntero inicio que vale NULL), los punteros inicio y fin apuntaran
hacia el nuevo elemento y el tamao es actualizado.

La funcin:
/* insercin en una lista vaca */
int ins_en_lista_vacia (Lista * lista, char *dato){
Element *nuevo_elemento;
if ((nuevo_elemento = (Element *) malloc (sizeof (Element))) == NULL)
return -1;
if ((nuevo _elemento->dato = (char *) malloc (50 * sizeof (char)))
== NULL)
return -1;
strcpy (nuevo_elemento->dato, dato);
nuevo_elemento->siguiente = NULL;
lista->inicio = nuevo_elemento;
lista->fin = nuevo_elemento;
lista->tamao++;
return 0;
}

Insercin al inicio de la lista


Ejemplo de la funcin:
int ins_inicio_lista (Lista *lista,char *dato);
La funcin da -1 en caso de error, de lo contrario da 0.
Etapas: asignar memoria al nuevo elemento, rellenar el campo de datos de este
nuevo elemento, el puntero siguiente del nuevo elemento apunta hacia el primer
elemento, el puntero inicio apunta al nuevo elemento, el puntero fin no cambia, el
tamao es incrementado

La funcin:
/* insercin al inicio de la lista */
int ins_inicio_lista (Lista * lista, char *dato){
Element *nuevo_elemento;
if ((nuevo_elemento = (Element *) malloc (sizeof (Element))) == NULL)
return -1;
if ((nuevo_elemento->dato = (char *) malloc (50 * sizeof (char)))
== NULL)
return -1;
strcpy (nuevo_elemento->dato, dato);
nuevo_elemento->siguiente = lista->inicio
lista->inicio = nuevo_elemento;
lista->tamao++;
return 0;
}

Insercin al final de la lista


Ejemplo de la funcin:
int ins_fin_lista (Lista *lista, Element *actual, char *dato);
La funcin da -1 en caso de error, si no arroja 0.
Etapas: proporcionar memoria al nuevo elemento, rellenar el campo de datos del
nuevo elemento, el puntero siguiente del ltimo elemento apunta hacia el nuevo
elemento, el puntero fin apunta al nuevo elemento, el puntero inicio no vara, el
tamao es incrementado:

La funcin:
/*insercin al final de la lista */
int ins_fin_lista (Lista * lista, Element * actual, char *dato){
Element *nuevo_elemento;
if ((nuevo_elemento = (Element *) malloc (sizeof (Element))) == NULL)
return -1;
if ((nuevo_elemento->dato = (char *) malloc (50 * sizeof (char)))
== NULL)
return -1;
strcpy (nuevo_elemento->dato, dato);
actual->siguiente = nuevo_elemento;
nuevo_elemento->siguiente = NULL;
lista->fin = nuevo_elemento;
lista->tamao++;
return 0;
}
Insercin en otra parte de la lista
Ejemplo de la funcin:
int ins_lista (Lista *lista, char *dato,int pos);
La funcin arroja -1 en caso de error, si no da 0.
La insercin se efectuar despus de haber pasado a la funcin una posicin
como argumento.
Si la posicin indicada no tiene que ser el ltimo elemento. En ese caso se debe
utilizar la funcin de insercin al final de la lista.

Etapas: asignacin de una cantidad de memoria al nuevo elemento, rellenar el


campo de datos del nuevo elemento, escoger una posicin en la lista (la insercin
se har luego de haber elegido la posicin), el puntero siguiente del nuevo
elemento apunta hacia la direccin a la que apunta el puntero siguiente del
elemento actual, el puntero siguiente del elemento actual apunta al nuevo
elemento, los punteros inicio y fin no cambian, el tamao se incrementa en una
unidad:

La funcin:
/* insercin en la posicin solicitada */
int ins_lista (Lista * lista, char *dato, int pos){
if (lista->tamao < 2)
return -1;
if (pos < 1 || pos >= lista->tamao)
return -1;
Element *actual;
Element *nuevo_elemento;
int i;
if ((nuevo_elemento = (Element *) malloc (sizeof (Element))) == NULL)
return -1;
if ((nuevo_elemento->dato = (char *) malloc (50 * sizeof (char)))
== NULL)
return -1;
actual = lista->inicio;
for (i = 1; i < pos; ++i)
actual = actual->siguiente;
if (actual->siguiente == NULL)
return -1;
strcpy (nuevo_elemento->dato, dato);
nuevo_elemento->siguiente = actual->siguiente;
actual->siguiente = nuevo_elemento;
lista->tamao++;
return 0;
9

Eliminacin de un elemento de la lista


Para eliminar un elemento de la lista: uso de un puntero temporal para almacenar
la direccin de los elementos a borrar, el elemento a eliminar se encuentra
despus del elemento actual, apuntar el puntero siguiente del elemento actual en
direccin del puntero siguiente del elemento a eliminar, liberar la memoria ocupada
por el elemento borrado, actualizar el tamao de la lista.
Para eliminar un elemento de la lista hay varios casos: eliminacin al inicio de la
lista y eliminacin en otra parte de la lista.
Eliminacin al inicio de la lista
Ejemplo de la funcin:
int sup_inicio (Lista *lista);
La funcin devolver -1 en caso de equivocacin, de lo contrario da 0.
Etapas: el puntero sup_elem contendr la direccin del 1er elemento, el puntero
inicio apuntara hacia el segundo elemento, el tamao de la lista disminuir un
elemento:

10

La funcin:
/* eliminacin al inicio de la lista */
int sup_inicio (Lista * lista){
if (lista->tamao == 0)
return -1;
Element *sup_elemento;
sup_element = lista->inicio;
lista->inicio = lista->inicio->siguiente;
if (lista->tamao == 1)
lista->fin = NULL;
free (sup_elemento->dato);
free (sup_elemento);
lista->tamao--;
return 0;
}
11

Eliminacin en otra parte de la lista


Ejemplo de la funcin:
int sup_en_lista (Lista *lista, int pos);
La funcin da -1 en caso de error, si no devuelve 0.
Etapas: el puntero sup_elem contendr la direccin hacia la que apunta el puntero
siguiente del elemento actual, el puntero siguiente del elemento actual apuntara
hacia el elemento al que apunta el puntero siguiente del elemento que sigue al
elemento actual en la lista. Si el elemento actual es el penltimo elemento, el
puntero fin debe ser actualizado. El tamao de la lista ser disminuido en un
elemento:

12

La funcin:
/* eliminar un elemento despus de la posicin solicitada */
13

int sup_en_lista (Lista * lista, int pos){


if (lista->tamao <= 1 || pos < 1 || pos >= lista->tamao)
return -1;
int i;
Element *actual;
Element *sup_elemento;
actual = lista->inicio;
for (i = 1; i < pos; ++i)
actual = actual->siguiente;
sup_elemento = actual->siguiente;
actual->siguiente = actual->siguiente->siguiente;
if(actual->siguiente == NULL)
lista->fin = actual;
free (sup_elemento->dato);
free (sup_elemento);
lista->tamao--;
return 0;
}
Visualizacin de la lista
Para mostrar la lista entera hay que posicionarse al inicio de la lista (el puntero
inicio lo permitir). Luego usando el puntero siguiente de cada elemento la lista es
recorrida del primero al ltimo elemento.
La condicin para detener es proporcionada por el puntero siguiente del ltimo
elemento que vale NULL.
La funcin:
/* visualizacin de la lista */
void visualizacin (Lista * lista){
Element *actual;
actual = lista->inicio;
while (actual != NULL){
printf ("%p - %s\n", actual, actual->dato);
actual = actual->siguiente;
}
}
Destruccin de la lista
Para destruir la lista entera, he utilizado la eliminacin al inicio de la lista porque el
tamao es mayor a cero.
14

La funcin
/* destruir la lista */
void destruir (Lista *lista){
while (lista->tamao > 0)
sup_inicio (lista);
}
Pilas
Las pilas son otro tipo de estructura de datos lineales, las cuales presentan
restricciones en cuanto a la posicin en la cual pueden realizarse las inserciones y
las extracciones de elementos.
Una pila es una lista de elementos en la que se pueden insertar y eliminar
elementos slo por uno de los extremos. Como consecuencia, los elementos de
una pila sern eliminados en orden inverso al que se insertaron. Es decir, el ltimo
elemento que se meti a la pila ser el primero en salir de ella.
Una pila es un tipo especial de lista abierta en la que slo se pueden insertar y
eliminar nodos en uno de los extremos de la lista. Estas operaciones se conocen
como "push" y "pop", respectivamente "empujar" y "tirar". Adems, las escrituras
de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el
nodo ledo.
Estas caractersticas implican un comportamiento de lista LIFO (Last In First Out),
el ltimo en entrar es el primero en salir.

Tipo de dato Abstracto Pila.

15

Tipo de dato Abstracto Pila en el que los elementos de almacenan de manera


secuencial, no existen bifurcaciones al momento de acceder a los datos, se
acceden por medio de la direccin de memoria. Los elementos se pueden insertar
o acceder por un nico extremo llamado tope, por esta razn las pilas se conocen
como un TDA de acceso restringido. Solo se puede eliminar o insertar por el tope.
Pilas con vectores.
Implementacin de pila:
#define tam_max 20 /*el tamao maximo sera 20. se puede cambiar*/
typedef char elemento; /*va a ser una pila de caracteres*/
typedef struct {
int tope;
elemento v[tam_max];
} pila;
El tipo elemento variar dependiendo del programa, as como tam_max.
Operaciones:
Vacia:
int vacia(pila1)
pila pila1;
{
if(pila1.tope==tam_max){
return 1;
}
else{
return 0;
}
}/*Fin esta vacia*/
Esta funcin devuelve 1 si la pila est vaca y 0 si no lo est.
llena:
int llena(pila1)
pila pila1;
{
if((pila1.tope)==0){
return 1;
}
else{
return 0;
}
16

}/*fin llena*/
Esta funcin devuelve 1 si la pila est llena y 0 si no lo est.
sacar:
int sacar(punt_pila)
pila *punt_pila;
{
int vacia();
int valor_vacia;
valor_vacia=vacia(*punt_pila);
if(valor_vacia==1){
return 0;
}
else{
(*punt_pila).tope=(*punt_pila).tope+1;
return 1;
}
}/*fin sacar*/
Esta funcin elimina el elemento cima de la pila y devuelve 1 si la pila no est
vaca y simplemente devuelve 0 si la pila est vaca. (Aplicar SACAR a una
pila vaca la deja igual).
Meter:
int meter(lo_que_meto,punt_pila)
elemento lo_que_meto;
pila *punt_pila;
{
int llena();
int copia_tope;
int valor_llena;
valor_llena=llena(*punt_pila);
if(valor_llena==1){
return 0;
}
else{
copia_tope=(*punt_pila).tope;
(*punt_pila).v[copia_tope-1]=lo_que_meto;
(*punt_pila).tope=copia_tope-1;
return 1;
}
}/*Fin meter*/
17

Esta funcin mete el elemento lo_que_meto en la pila y devuelve 1 si no est


vaca y simplemente devuelve 0 si est llena.
Cima:
elemento cima(pila1) /*1 hay q asegurarse d q no est vaca*/
pila pila1;
{
int vacia();
int copia_tope;
if(vacia(pila1)==0){ /*si no esta vacia se procede*/
copia_tope=pila1.tope;
return pila1.v[copia_tope];}
else{
printf("\n Error. Has aplicado la funcion cima a una pila vacia\n");
return pila1.v[1];}/*esto ultimo es absurdo, pues la pila esta vacia, pero te ahorra
un warning al compilar*/
}/*Fin Cima*/
Esta funcin devuelve el elemento cima si la pila no est vaca y devuelve un
elemento de tipo elemento si est vaca dando un mensaje de error. Por eso hay
que asegurarse de que la pila no est vaca antes de llamar a Cima.
Pila como Lista Enlazada
typedef char elemento;/*defino elemento como char. se puede cambiar*/
typedef struct Node{
/*defino el tipo nodo como registro de info y sgte*/
elemento info; /*en ppio las pilas seran de char, pero esto se puede
cambiar*/
struct Node *sgte;
};
typedef struct Node nodo;
typedef nodo *pila; /*defino el tipo pila como puntero a nodo*/
El tipo elemento variar segn el programa.
Operaciones:
Vacia:
int vacia(pila1)
pila pila1;
{
if (pila1==NULL)
else return 0;
}/*Fin vacia*/

return 1;

18

Vaca devuelve 1 si la pila est vaca y 0 si no lo est.


Sacar:
int sacar(punt_pila)
pila *punt_pila;
{
int vacia();
pila aux_pila;
if(vacia(*punt_pila)==1){
return 0;
}
else{ /* (*punt_pila)es igual a pila1, q es un puntero al 1er nodo, luego quiero
modificar su contenido: */
aux_pila=(*(*punt_pila)).sgte;
free(*punt_pila);
*punt_pila=aux_pila;
return 1;
}
}/*Fin sacar*/
Sacar saca un elemento de la pila si no est vaca devolviendo 1 o devuelve 0 si
est vaca.
Meter:
int meter(lo_que_meto,punt_pila)
elemento lo_que_meto;
pila *punt_pila;
{
pila aux_pila;
aux_pila=*punt_pila; /*asi me hago una copia de pila1 en aux_pila*/
*punt_pila=(nodo*)calloc(1,sizeof(nodo)); /* pila1=*punt_pila */
if(*punt_pila==NULL){
printf("\n Error. No se puede reservar mas espacio.");
return 0;
}
else{ /*se ha podido reservar espacio para un nodo: se procede a meter*/
(*(*punt_pila)).info=lo_que_meto; /* (**punt_pila) apunta al 1er nodo*/
(*(*punt_pila)).sgte=aux_pila; /*para q el 1er nodo apunte al q ahora es el
2*/
return 1;
}
}/*Fin meter*/
19

Meter mete lo_que_meto en la pila en caso de que no est llena devolviendo un 1


o da un mensaje de error y devuelve un 0 en caso de que no haya ms espacio en
memoria para otro nodo.
Cima:
elemento cima(pila1)
pila pila1;
{
int vacia();
if(vacia(pila1)==0){/*no vacia*/
return ((*pila1).info);}
else{
printf("\n Error. Has aplicado la funcion cima a una pila vacia\n");
return ((*pila1).info);}/*esto ultimo es absurdo, pues la pila esta vacia, pero
te ahorra un warning al compilar*/} /*Fin vacia*/
Cima devuelve el elemento cima de una pila no vaca. Si se aplica sobre una
funcin vaca el programa aborta, as que hay que asegurarse antes de ejecutarla.
Ejemplo Pilas:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
struct agenda
{
char nombre[50];
char telefono[25];
char mail[50];
};
struct nodo
{
struct agenda dato;
struct nodo *proximo;
};
struct nodo *nuevonodo();
int colavacia(struct nodo *);
20

struct nodo *creacola(struct nodo *, struct agenda);


void mostrar(struct nodo *);
void main()
{
struct nodo *pri=NULL, *ult=NULL;
struct agenda x;
printf("Ingrese nombre: ");
gets(x.nombre);
while(strcmpi(x.nombre,"fin"))
{
printf("Ingrese telefono: ");
gets(x.telefono);
printf("Ingrese mail: ");
gets(x.mail);
ult=creacola(ult,x);
if(pri==NULL) pri=ult; // Si es la 1 pasada pongo en pri el valor del primer
nodo
printf("Ingrese nombre: ");
gets(x.nombre);
}
if(colavacia(pri)==1) { printf("No se ingresaron registros"); getch(); }
else mostrar(pri);
}
struct nodo *nuevonodo()
{
struct nodo *p;
p=(struct nodo *)malloc(sizeof(struct nodo));
if(p==NULL)
{
printf("Memoria RAM Llena");
getch();
exit(0);
}
return p;
}
struct nodo *creacola(struct nodo *ult, struct agenda x)
{
struct nodo *p;
21

p=nuevonodo();
(*p).dato=x;
(*p).proximo=NULL;
if(ult!=NULL) (*ult).proximo=p; // Si hay nodo anterior en prox pongo la
direccion del nodo actual
return p;
}
int colavacia(struct nodo *pri)
{
if(pri==NULL) return 1;
else return 0;
}
void mostrar(struct nodo *pri)
{
struct nodo *aux;
while(pri!=NULL)
{
printf("Nombre: %s - Telefono: %s - Mail: %s \n",pri->dato.nombre,pri>dato.telefono,pri->dato.mail);
aux=pri;
pri=(*pri).proximo;
free(aux);
}
getch();
}

Colas.

22

Una cola es una coleccin de elementos homogneos (almacenados en dicha


estructura), en la misma se pueden insertar elementos por uno de los extremos,
llamado frente, y retirar los mismos por el otro extremo, denominado final.
Es importante aclarar que, tanto el frente como el final de la cola, son los nicos
indicados para retirar e insertar elementos, respectivamente. Esto nos indica que
no podemos acceder directamente a cualquier elemento de la cola, sino solo al
primero, o sea el que est o se encuentra en el frente, y no se pueden insertar
elementos en cualquier posicin sino solo por el final, as el elemento insertado
queda como ltimo.
Por esta razn la cola es denominada una estructura F.I.F.O., o simplemente una
lista F.I.F.O., esto representa el acrnimo de las palabras inglesas first in, first out
(primero en entrar, primero en salir).
Las colas se utilizan en sistemas informticos, transportes y operaciones de
investigacin (entre otros), dnde los objetos, personas o eventos son tomados
como datos que se almacenan y se guardan mediante colas para su posterior
procesamiento. Este tipo de estructura de datos abstracta se implementa en
lenguajes orientados a objetos mediante clases, en forma de listas enlazadas.
Usos concretos de la cola
La particularidad de una estructura de datos de cola es el hecho de que slo
podemos acceder al primer y al ltimo elemento de la estructura. As mismo, los
elementos slo se pueden eliminar por el principio y slo se pueden aadir por el
final de la cola.
Operaciones Bsicas

Crear: se crea la cola vaca.


Encolar (aadir, entrar, insertar): se aade un elemento a la cola. Se
aade al final de esta.
Desencolar (sacar, salir, eliminar): se elimina el elemento frontal de la
cola, es decir, el primer elemento que entr.
Frente (consultar, front): se devuelve el elemento frontal de la cola, es
decir, el primer elemento que entr.

Esta es una variacin de la implementacin en el libro C & Data Structures de una


cola ( FIFO ) construida sobre un array. Me intereso esa estructura de datos por 2
23

cosas. Primero, el hecho de que la estructura de datos era ms que el array donde
se guardaban los datos, necesitndose una serie de variables asociados para
usarlo y segundo el uso de la aritmtica mod( n ) para moverse entre las
posiciones del array.
Sin embargo, existen una serie de errores en la implementacin del ejemplo y
adems considerando que se utilizan un conjunto de variables para definir el
funcionamiento de la estructura, lo lgico sera agrupar todas estas variables
dentro de un struct de C. As que esta es una implementacin, en la sintaxis de
punteros y de structs en C:
#include <stdio.h>
#include <stdlib.h>
#define MAX 10 /* The maximum size of the queue */
struct ca {
int cola[ MAX ];
int fin;
int frente;
int num_elems;
};
typedef struct ca cola_array;

void insert( cola_array *carr, int value ) {


if(carr->frente == carr->fin && carr->num_elems > 0) {
printf("Cola Llenan");
} else {
carr->cola[ carr->fin ] = value;
carr->fin = ( carr->fin + 1) % MAX;
carr->num_elems ++;
}
}
int delete( cola_array *carr ) {
int temp;
if( carr->num_elems == 0 ) {
printf("Cola Vacian");
return -1;
} else {
temp = carr->cola[ carr->frente ];
24

carr->frente = ( carr->frente + 1) % MAX;


carr->num_elems--;
return temp;
}
}
void listar( cola_array *carr ) {
int x;
if( carr->num_elems == 0 ) {
printf("Cola Vacia");
} else {
printf("Numero de Elementos: %dt Frente: %dt Fin: %dn", carr>num_elems, carr->frente, carr->fin);
for( x = 0; x < carr->num_elems; x++) {
printf("%dt", carr->cola[ ( x + carr->frente ) % MAX ]);
}
}
printf("n");
}
int main()
{
int menu, value;
cola_array carr;
carr.fin = carr.frente = carr.num_elems = 0;
do {
printf("Seleccione:n");
printf("1. Insertarn");
printf("2. Borrarn");
printf("3. Listarn");
printf("4. Salirn");
scanf("%d", &menu);
switch(menu) {
case 1:
printf("Valor a Insertar (Mayor o Igual que 0): n");
scanf("%d", &value);
insert( &carr, value);
break;
case 2:
value = delete( &carr );
if(value >= 0) {
25

printf("Valor borrado: %d n", value);


}
break;
case 3:
listar( &carr );
break;
case 4:
return(0);
break;
default:
printf("Opcion no Valida.n");
break;
}
} while( menu != 4 );
return(0);
}
La parte que ms importante es esta:
for( x = 0; x < carr->num_elems; x++) {
printf("%dt", carr->cola[ ( x + carr->frente ) % MAX ]);
}
Y en particular ( x + carr->frente ) % MAX por el uso de la aritmtica mod( n ) que
me hizo recordar al concepto de clases de equivalencias de Algebra
Explicacin:
Supongamos que la cola tiene 5 elementos (sobre un mximo de 10), pero como
la cola ya se estuvo utilizando quedaron ubicados los 2 primeros en las posiciones
8 y 9 del array y los 3 ltimos en las posiciones 0 a 2. El loop va a iterar a x de 0 a
4, cuando x este en 0 ( x + carr->frente ) % MAX va a equivaler a 8, cuando este
en 1 a 9; pero cuando llegue a 2, ( x + carr->frente ) equivale a 10 y 10 % MAX
equivale a 0.
Esto es as porque en la 0/10, 10/10, 20/10.. etc, tienen exactamente el mismo
resto, 0; de la misma manera que 1/10, 11/10, 21/10.. etc tienen todos resto 1. ( La
operacin % establece clases de equivalencia sobre N). Lo que permite moverse
circularmente sobre el array.
Colas como Listas enlazadas
26

Para hacer la implementacin se utilizar una lista circular sin cabecera.


La cola estar inicialmente vaca. Cuando se aadan elementos el puntero que
mantiene la cola apunta al ltimo elemento introducido, y el siguiente elemento al
que apunta es al primero que est esperando para salir.
- Cmo encolar? Se crea el nuevo elemento, se enlaza con el primero de la cola.
Si no est vaca hay que actualizar el enlace del, hasta el momento de la
insercin, ltimo elemento introducido. Por ltimo se actualiza el comienzo de la
cola, est vaca o no.
- Cmo desencolar? Si tiene un slo elemento se borra y se actualiza el puntero
a un valor nulo. Si tiene dos o ms elementos entonces se elimina el primero y el
ltimo apuntar al segundo.
Ejemplo grfico de encolado. Partiendo de una cola que tiene el elemento 3, se
van aadiendo el 5 y el 7 (observar de izquierda a derecha). A la hora de
desencolar se extrae el siguiente al que apunta Cola.

Ejemplo grfico de desencolado. Partiendo de la cola formada anteriormente, se


han quitado los dos primeros elementos introducidos (observar de izquierda a
derecha).

- Declaracin:
struct tcola
{
int clave;
struct tcola *sig;
27

};

- Creacin:
void crear(struct tcola **cola)
{
*cola = NULL;
}

- Funcin que devuelve cierto si la cola est vaca:


int vacia(struct tcola *cola)
{
return (cola == NULL);
}
- Encolado:
void encolar(struct tcola **cola, int elem)
{
struct tcola *nuevo;
nuevo = (struct tcola *) malloc(sizeof(struct tcola));
nuevo->clave = elem;
if (*cola == NULL)
nuevo->sig = nuevo;
else {
nuevo->sig = (*cola)->sig;
(*cola)->sig = nuevo;
}
(*cola) = nuevo;
}
- Desencolado:
void desencolar(struct tcola **c1, int *elem)
{
struct tcola *aux;
28

*elem = (*c1)->sig->clave;
if ((*c1) == (*c1)->sig) {
free(*c1);
*c1 = NULL;
}
else {
aux = (*c1)->sig;
(*c1)->sig = aux->sig;
free(aux);
}
}

- Programa de prueba:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
struct tcola *cola;
int elem;
crear(&cola);
if (vacia(cola)) printf("\nCola vacia!");
encolar(&cola, 3);
desencolar(&cola, &elem);
return 0;
}
Ver colasle.c para tener una implementacin completa con listas enlazadas.
Al igual que en las pilas implementadas por listas enlazadas, es recomendable
analizar el cdigo devuelto por la funcin de asignacin de memoria para evitar
posibles problemas en un futuro.

Otras consideraciones
29

En algunos casos puede ser interesante implementar una funcin para contar el
nmero de elementos que hay en la cola. Una manera de hacer esto con listas
enlazadas es empleando la siguiente declaracin:
struct nodo
{
int clave;
struct nodo *sig;
};
struct tcola
{
int numero_elems; /* mantiene el numero de elementos */
struct nodo *cola;
};
Qu implementacin es mejor, arrays o listas?
Al igual que con las pilas, la mejor implementacin depende de la situacin
particular. Si se conocen de antemano el nmero de elementos entonces lo ideal
es una implementacin por array. En otro caso se recomienda el uso de lista
enlazada circular.

30