Tipos de Datos Abstractos


TDA LISTAS


DEFINICION DE LISTA SIMPLE

Las listas enlazadas son estructuras de datos semejantes a los array salvo que el acceso a un elemento no se hace mediante un indice sino mediante un puntero. La asignación de memoria es hecha durante la ejecución.
En una lista los elementos son contiguos en lo que concierne al enlazado.
En cambio, mientras que en un array los elementos están contiguos en la memoria, en una lista los elementos están dispersos. 
El enlace entre los elementos se hace mediante un puntero. 
En realidad, en la memoria la representación es aleatoria en función del espacio asignado. 
El puntero siguiente del último elemento debe apuntar hacia NULL (el fin de la lista). Para acceder a un elemento, la lista es recorrida comenzando por el inicio, el puntero siguiente permite el desplazamiento hacia el próximo elemento. El desplazamiento se hace en una sola dirección, del primer al último elemento. 
Si se desea desplazar en las dos direcciones (hacia delante y hacia atrás) se  debe utilizar las listas doblemente enlazadas.



CONSTRUCCIÓN DEL MODELO DE UN ELEMENTO DE LA LISTA SIMPLE


Para definir un elemento de la lista, será utilizado el tipo struct. El elemento de la lista contendrá un campo dato y un puntero siguiente.
El puntero siguiente debe ser del mismo tipo que el elemento, si no, no podrá apuntar hacia el elemento. El puntero siguiente permitirá el acceso al próximo elemento. 

typedef struct ElementoLista
{  char   *dato;
    struct ElementoLista *siguiente;
}Elemento;



Para tener el control de la lista es preferible guardar ciertos elementos: El primer elemento, el último elemento, el número de elementos. 
Para ello será utilizado otra estructura (no es obligatorio, pueden ser utilizadas variables) 

typedef struct ListaIdentificar
{  Elemento *inicio;
   Elemento *fin;
   int tamaño;
}Lista;



El puntero inicio contendrá la dirección del primer elemento de la lista.  El puntero fin contendrá la dirección del último elemento de la lista. La variable tamaño contiene el número de elementos. Cualquiera que sea la posición en la lista, los punteros inicio y fin apuntan siempre al primer y último elemento.  El campo tamaño contendrá el número de elementos de la lista cualquiera que sea la operación efectuada sobre la lista. 



OPERACIONES SOBRE LAS LISTAS ENLAZADAS SIMPLES

INICIALIZACIÓN

void inicializacion (Lista *lista);

Esta operación debe ser hecha antes de cualquier otra operación sobre la lista. Esta inicializa el puntero inicio y el puntero fin con el puntero NULL, y el tamaño con el valor 0. 

void inicializacion (Lista *lista)
{
lista->inicio = NULL;
lista->fin = NULL;
tamaño = 0;
}


INSERCIÓN DE UN ELEMENTO EN LA LISTA

Para añadir un elemento a la lista hay varios casos:

1. Inserción en una lista vacía
2. Inserción al inicio de la lista
3. Inserción al final de la lista
4. Inserción en otra parte de la lista.


Inserción en una lista vacía

int ins_en_lista_vacia (Lista *lista, char *dato);


La función devuelve 1 en caso de error, si no devuelve 0. 
Etapas:
1.        Asignación de memoria para el nuevo elemento
2.        Rellenar el campo de datos del nuevo elemento
3.        El puntero siguiente del nuevo elemento apuntará hacia NULL (ya que la inserción es hecha en una lista vacía se utiliza la dirección del puntero inicio que vale NULL)
4.        Los punteros inicio y fin apuntaran hacia el nuevo elemento
5.        El tamaño es actualizado

 
Función insertar en una lista vacía

/* inserción en una lista vacía */
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->tamaño++;
  return 0;
}
Inserción al inicio de la lista
int ins_inicio_lista (Lista *lista,char *dato);

La función devuelve -1 en caso de error, si no devuelve 0.
Etapas:
Asignación de memoria al nuevo elemento
Rellenar el campo de datos del nuevo elemento
        El puntero siguiente del nuevo elemento apunta hacia el primer elemento
        El puntero inicio apunta hacia el nuevo elemento
        El puntero fin no cambia
        El tamaño es incrementado


/* inserción 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->tamaño++;
  return 0;
}
Inserción al final de la lista
int ins_fin_lista (Lista *lista, Element *actual, char *dato);

La función devuelve -1 en caso de error, si no devuelve 0. 
Etapas:
1.        asignación de memoria al nuevo elemento
2.        rellenar el campo de datos del nuevo elemento
3.        el puntero siguiente del último elemento apunta hacia el nuevo elemento
4.        el puntero fin apunta hacia el nuevo elemento
5.        el puntero inicio no cambia
6.        el tamaño es incrementado


/*inserción 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->tamaño++;
  return 0;
}
Inserción en otra parte de la lista
int ins_lista (Lista *lista, char *dato,int pos);


La función devuelve -1 en caso de error, si no devuelve 0. La inserción se efectuará después de haber pasado a la función una posición como argumento. Si la posición indicada no tiene que ser el último elemento. En ese caso hay que utilizar la función de inserción al final de la lista. 
Etapas:
1.        Asignación de memoria al nuevo elemento
2.        Rellenar el campo de datos del nuevo elemento
3.        Elegir una posición en la lista (la inserción se hará después de haber elegido la posición)
4.        El puntero siguiente del nuevo elemento apunta hacia la dirección a la que apunta el punteros siguiente del elemento actual.
5.        El puntero siguiente del elemento actual apunta al nuevo elemento
6.        Los punteros inicio y fin no cambian
7.        El tamaño se incrementa en una unidad

/* inserción en la posición solicitada */
int ins_lista (Lista * lista, char *dato, int pos){
  if (lista->tamaño < 2)
    return -1;
  if (pos < 1 || pos >= lista->tamaño)
    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->tamaño++;
  return 0;


Eliminación de un elemento de la lista

1.        Uso de un puntero temporal para guardar la dirección de los elementos a eliminar
2.        El elemento a eliminar se encuentra después del elemento actual
3.        Apuntar el puntero siguiente del elemento actual hacia la dirección del puntero siguiente del elemento a eliminar
4.        Liberar la memoria ocupada por el elemento eliminado
5.        Actualizar el tamaño de la lista

Para eliminar un elemento de la lista hay varios casos:
1. Eliminación al inicio de la lista
2. Eliminación en otra parte de la lista


Eliminación al inicio de la lista
int sup_inicio (Lista *lista);

La función devuelve -1 en caso de error, si no devuelve 0.
Etapas:
1.        El puntero sup_elem contendrá la dirección del 1er elemento
2.        El puntero inicio apuntara hacia el 2do elemento
3.        El tamaño de la lista disminuirá un elemento


/* eliminación al inicio de la lista */
int sup_inicio (Lista * lista){
  if (lista->tamaño == 0)
    return -1;
  Element *sup_elemento;
  sup_element = lista->inicio;
  lista->inicio = lista->inicio->siguiente;
  if (lista->tamaño == 1)
    lista->fin = NULL;
  free (sup_elemento->dato);
  free (sup_elemento);
  lista->tamaño--;
  return 0;
}


Eliminación en otra parte de la lista
int sup_en_lista (Lista *lista, int pos);

La función devuelve -1 en caso de error, si no devuelve 0.
Etapas:
1.        El puntero sup_elem contendrá la dirección hacia la que apunta el puntero siguiente del elemento actual
2.        El puntero siguiente del elemento actual apuntara hacia el elemento al que apunta el punteros siguiente del elemento que sigue al elemento actual en la lista.
3.        El tamaño de la lista será disminuido en un elemento

/* eliminar un elemento después de la posición solicitada */
int sup_en_lista (Lista * lista, int pos){
  if (lista->tamaño <= 1 || pos < 1 || pos >= lista->tamaño)
    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->tamaño--;
  return 0;
}


Visualización de la lista

Para mostrar la lista entera hay que posicionarse al inicio de la lista (el puntero inicio lo permitirá). Luego utilizando el puntero siguiente de cada elemento la lista es recorrida del 1ero al último elemento. La condición para detener es dada por el puntero siguiente del último elemento que vale NULL. 


/* visualización de la lista */
void visualización (Lista * lista){
  Element *actual;
  actual = lista->inicio;
  while (actual != NULL){
      printf ("%p - %s\n", actual, actual->dato);
      actual = actual->siguiente;
  }
}


Destrucción de la lista

Para destruir la lista entera, he utilizado la eliminación al inicio de la lista ya que el tamaño es mayor a cero.

/* destruir la lista */
void destruir (Lista * lista){
  while (lista->tamaño > 0)
    sup_inicio (lista);
}


LISTAS DOBLEMENTE ENLAZADAS


Una lista doblemente enlazada es una lista lineal en la que cada nodo tiene dos enlaces, uno al nodo siguiente, y otro al anterior.
Las listas doblemente enlazadas no necesitan un nodo especial para acceder a ellas, pueden recorrerse en ambos sentidos a partir de cualquier nodo, esto es porque a partir de cualquier nodo, siempre es posible alcanzar cualquier nodo de la lista, hasta que se llega a uno de los extremos. El nodo típico es el mismo que para construir las listas que hemos visto, salvo que tienen otro puntero al nodo anterior:

struct nodo
{   int dato;
    struct nodo *siguiente;
    struct nodo *anterior;
 };

 

DECLARACIONES DE TIPOS PARA MANEJAR LISTAS DOBLEMENTE ENLAZADAS


typedef struct _nodo \{
   int dato;
   struct _nodo *siguiente;
   struct _nodo *anterior;
} tipoNodo;

typedef tipoNodo *pNodo;
typedef tipoNodo *Lista;

ü  tipoNodo es el tipo para declarar nodos, evidentemente.
ü  pNodo es el tipo para declarar punteros a un nodo.
ü  Lista es el tipo para declarar listas abiertas doblemente enlazadas. También es posible, y potencialmente útil, crear listas doblemente enlazadas y circulares.

  
OPERACIONES SOBRE LAS LISTAS ENLAZADAS

·         Añadir o insertar elementos.
·         Buscar o localizar elementos.
·         Borrar elementos.
·         Moverse a través de la lista, siguiente y anterior.

Añadir un elemento

Nos encontramos ahora ante un tipo de estructura algo diferente de las que hemos estado viendo, así que entraremos en más detalles.
Vamos a intentar ver todos los casos posibles de inserción de elementos en listas doblemente enlazadas.


Añadir elemento en una lista doblemente enlazada vacía

Partiremos de que ya tenemos el nodo a insertar y, por supuesto un puntero que apunte a él, además el puntero que define la lista, que valdrá NULL

El proceso es muy simple, bastará con que:
1.        lista apunta a nodo.
2.        lista->siguiente y lista->anterior apunten a null.

Insertar un elemento en la primera posición de la lista
Partimos de una lista no vacía. Para simplificar, consideraremos que lista apunta al primer elemento de la lista doblemente enlazada
El proceso es el siguiente:
1.        nodo->siguiente debe apuntar a Lista.
2.        nodo->anterior apuntará a Lista->anterior.
3.        Lista->anterior debe apuntar a nodo.


Insertar un elemento en la última posición de la lista

Igual que en el caso anterior, partiremos de una lista no vacía, y de nuevo para simplificar, que Lista está apuntando al último elemento de la lista.
El proceso es el siguiente:
1.        nodo->siguiente debe apuntar a Lista->siguiente (NULL).
2.        Lista->siguiente debe apuntar a nodo.
3.        nodo->anterior apuntará a Lista.

Insertar un elemento a continuación de un nodo cualquiera de una lista

Bien, este caso es más genérico, ahora partimos de una lista no vacía, e insertaremos un nodo a continuación de uno nodo cualquiera que no sea el último de la lista
El proceso sigue siendo muy sencillo:
1.        Hacemos que nodo->siguiente apunte a lista->siguiente.
2.        Hacemos que Lista->siguiente apunte a nodo.
3.        Hacemos que nodo->anterior apunte a lista.
4.        Hacemos que nodo->siguiente->anterior apunte a nodo.

Añadir elemento en una lista doblemente enlazada, caso general

Para generalizar todos los casos anteriores, sólo necesitamos añadir una operación:
1.        Si lista está vacía hacemos que Lista apunte a nodo. Y nodo->anterior y nodo->siguiente a NULL.
2.        Si lista no está vacía, hacemos que nodo->siguiente apunte a Lista->siguiente.
3.        Después que Lista->siguiente apunte a nodo.
4.        Hacemos que nodo->anterior apunte a Lista.
5.        Si nodo->siguiente no es NULL, entonces hacemos que nodo->siguiente->anterior apunte a nodo.
6.         
El paso 1 es equivalente a insertar un nodo en una lista vacía.
Los pasos 2 y 3 equivalen a la inserción en una lista enlazada corriente.
Los pasos 4, 5 equivalen a insertar en una lista que recorre los nodos en sentido contrario.

Ejemplo de Inserción

1.        El primer paso es crear un nodo para el dato que vamos a insertar.
2.        Si Lista está vacía, o el valor del primer elemento de la lista es mayor que el del nuevo, insertaremos el nuevo nodo en la primera posición de la lista.
3.        En caso contrario, buscaremos el lugar adecuado para la inserción, tenemos un puntero "anterior". Lo inicializamos con el valor de Lista, y avanzaremos mientras anterior->siguiente no sea NULL y el dato que contiene anterior->siguiente sea menor o igual que el dato que queremos insertar.
4.        Ahora ya tenemos anterior señalando al nodo adecuado, así que insertamos el nuevo nodo a continuación de él.

void Insertar(Lista *lista, int v) \{
   pNodo nuevo, actual;

   /* Crear un nodo nuevo */
   nuevo = (pNodo)malloc(sizeof(tipoNodo));
   nuevo->valor = v;
  
   /* Colocamos actual en la primera posición de la lista */
   actual = *lista;
   if(actual) while(actual->anterior) actual = actual->anterior;
  
   /* Si la lista está vacía o el primer miembro es mayor que el nuevo */
   if(!actual || actual->valor > v) \{
      /* Añadimos la lista a continuación del nuevo nodo */
      nuevo->siguiente = actual;
      nuevo->anterior = NULL;
      if(actual) actual->anterior = nuevo;
      if(!*lista) *lista = nuevo;
   }
   else \{
      /* Avanzamos hasta el último elemento o hasta que el siguiente tenga
         un valor mayor que v */
      while(actual->siguiente &&actual->siguiente->valor <= v)
         actual = actual->siguiente;
      /* Insertamos el nuevo nodo después del nodo anterior */
      nuevo->siguiente = actual->siguiente;
      actual->siguiente = nuevo;
      nuevo->anterior = actual;
      if(nuevo->siguiente) nuevo->siguiente->anterior = nuevo;
   }
}


Ejemplo de Borrar

void Borrar(Lista *lista, int v) \{
   pNodo nodo;
  
   /* Buscar el nodo de valor v */
   nodo = *lista;
   while(nodo && nodo->valor <v) nodo = nodo->siguiente;
   while(nodo && nodo->valor > v) nodo = nodo->anterior;

   /* El valor v no está en la lista */
   if(!nodo || nodo->valor != v) return;
  
   /* Borrar el nodo */
   /* Si lista apunta al nodo que queremos borrar, apuntar a otro */
   if(nodo == *lista)
     if(nodo->anterior) *lista = nodo->anterior;
     else *lista = nodo->siguiente;
  
   if(nodo->anterior) /* no es el primer elemento */
      nodo->anterior->siguiente = nodo->siguiente;
   if(nodo->siguiente) /* no es el último nodo */
      nodo->siguiente->anterior = nodo->anterior;
   free(nodo);
}



TDA PILAS



La pila es una estructura de datos que permite almacenar datos en el orden LIFO (Last In First Out) en español, último en entrar, primero en salir). La recuperación de los datos es hecha en el orden inverso de su inserción. 
Para la implementación he elegido una lista enlazada simple, presentada sobre la vertical. Ya que la inserción es siempre hecha al inicio de la lista, el 1er elemento de la lista será el último elemento ingresado, por lo tanto estará en la cabeza de la pila. 
Lo interesante es que el último elemento ingresado, será el 1er elemento recuperado. 



CONSTRUCCIÓN DEL MODELO DE UN ELEMENTO DE LA PILA

Para definir un elemento de la pila será utilizado el tipo struct
El elemento de la pila contendrá un campo dato y un puntero siguiente
El puntero siguiente debe ser del mismo tipo que el elemento, de lo contrario no podrá apuntar hacia el elemento. 
El puntero siguiente permitirá el acceso al próximo elemento. 

typedef struct ElementoLista {
    char *dato;
    struct ElementoLista *siguiente;
}Elemento;

Para permitir las operaciones sobre la pila, vamos a guardar ciertos elementos:
·         El primer elemento
·         El número de elementos

El 1er elemento, que se encuentra en la cabeza de la pila, nos permitirá realizar la operación de recuperación de los datos situados en la parte superior de la pila. 
Para ello, será utilizada otra estructura (no es obligatorio, pueden ser utilizadas variables). 

typedef struct ListaUbicación{
  Elemento *inicio;
  int tamaño;
} Pila;


CONSTRUCCIÓN DEL MODELO DE UN ELEMENTO DE LA PILA

Inicialización

void inicialización (Pila *tas);

Esta operación debe ser hecha antes de cualquier otra operación sobre la pila. 
Esta inicializa el puntero inicio con el puntero NULL, y el tamaño con el valor 0. 

void inicialización (Pila * tas){
  tas->inicio = NULL;
  tas->tamaño = 0;
}

Inserción de un elemento en la pila

A continuación el algoritmo de inserción y registro de los elementos:
1.        Declaración del elemento a insertar
2.        Asignación de la memoria para el nuevo elemento
3.        Rellenar el contenido del campo de datos
4.        Actualizar el puntero inicio hacia el 1er elemento (la cabeza de la pila)
5.        Actualizar el tamaño de la pila.

int apilar (Pila *tas, char *dato);

Función añadir un nuevo elemento

/* apilar (añadir) un elemento en la pila */
int apilar (Pila * tas, char *dato){
  Elemento *nuevo_elemento;
  if ((nuevo_elemento = (Elemento *) malloc (sizeof (Elemento))) == NULL)
    return -1;
  if ((nuevo_elemento->dato = (char *) malloc (50 * sizeof (char)))
      == NULL)
    return -1;
  strcpy (nuevo_elemento->dato, dato);
  nuevo_elemento->siguiente = tas->inicio;
  tas->inicio = nuevo_elemento;
  tas->tamaño++;
}


Eliminar un elemento de la pila

Para eliminar un elemento de la pila, simplemente hay que eliminar el elemento hacia el cual apunta el puntero inicio.
Esta operación no permite recuperar el dato en la cabeza de la pila, solo eliminarlo. 

int desapilar (Pila *tas);

La función devuelve -1 en caso de error, si no devuelve 0. 
Las etapas:
1.        El puntero sup_elemento contendrá la dirección del 1er elemento
2.        El puntero inicio apuntará hacia el 2do elemento (después de la eliminación del 1er elemento, el 2do elemento estará en la cabeza de la pila)
3.        El tamaño de la pila disminuirá un elemento.

Funcion eliminar

int desapilar (Pila * tas){
  Elemento *sup_elemento;
  if (tas->tamaño == 0)
    return -1;
  sup_elemento = tas->inicio;
  tas->inicio = tas->inicio->siguiente;
  free (sup_elemento->dato);
  free (sup_elemento);
  tas->tamaño--;
  return 0;
}


Vizualizacion de la pila

Para mostrar la pila entera, es necesario posicionarse al inicio de la pila (el puntero inicio lo permitirá).
Luego, utilizando el puntero siguiente de cada elemento, la pila es recorrida del 1er hacia el último elemento.
La condición para detenerse es dada por el tamaño de la pila. 

/* visualización de la pila */
void muestra (Pila * tas){
  Elemento *actual;
  int i;
  actual = tas->inicio;

  for(i=0;i<tas->tamaño;++i){
    printf("\t\t%s\n", actual->dato);
    actual = actual->siguiente;
  }}

Recuperacion del dato en la cabeza

Para recuperar el dato en la cabeza de la pila sin eliminarlo, he utilizado una macro. La macro lee los datos en la parte superior de la pila utilizando el puntero inicio

#define pila_dato(tas)  tas->inicio->dato


typedef struct ElementoLista{
  char *dato;
  struct ElementoLista *siguiente;
} Elemento;

typedef struct ListaUbicación{
  Elemento *inicio;
  int tamaño;
} Pila;


/* inicialización */
void inicialización (Pila *tas);

/* APILAR*/
int apilar (Pile *tas, char *dato);

/* DESAPILAR*/
int desapilar (Pila *tas);

/* Visualización del elemento en la cabeza de la pila (LastInFirstOut) */
#define pila_dato(tas)  tas->inicio->dato

/* muestra la pila */
void muestra (Pila *tas);




TDA COLA

Una cola es un tipo especial de lista abierta en la que sólo se puede insertar nodos en uno de los extremos de la lista y sólo se pueden eliminar nodos en el otro. Además, como sucede con las pilas, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el nodo leído.
Este tipo de lista es conocido como lista FIFO (First In First Out), el primero en entrar es el primero en salir.
El símil cotidiano es una cola para comprar, por ejemplo, las entradas del cine. Los nuevos compradores sólo pueden colocarse al final de la cola, y sólo el primero de la cola puede comprar la entrada.

struct nodo
{
   int dato;
   struct nodo *siguiente;
};

DECLARACIONES DE TIPOS PARA MANEJAR COLAS EN C

Los tipos que definiremos normalmente para manejar colas serán casi los mismos que para manejar listas y pilas, tan sólo cambiaremos algunos nombres:

typedef struct _nodo
{
   int dato;
   struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Cola;

tipoNodo es el tipo para declarar nodos, evidentemente.
pNodo es el tipo para declarar punteros a un nodo.
Cola es el tipo para declarar colas.



#include<stdio.h>
#include<conio.h>
#include<stdlib.h>

void insertar_colas();
void imprimir_colas();
void eliminar_colas();

typedef struct nodoc
{
  int dato_colas;//donde se guarda el telefono
  int dura_colas;//donde se guarda el tiempo
  struct nodoc *sgte;//puntero siguiente
 
}nodoc;

long int fono;
int tiempo;
nodoc *act_1,*fin,*inicio_1=NULL;

main()
{
  int opcion;
 
  do
  {
    system("color "); 
    system("CLS");
    printf("\n\t\t\t\t***MENU***\n");
    printf("\n\n Trabajo Colas\n");
   
   
    printf(" ---Trabajar con COLAS---\n");
    printf("\n 1.- Realizar llamada");
    printf("\n 2.- Mostrar llamadas y su duracion:");
    printf("\n 3.- SALIR");
   
    printf("\n\n * Para Salir Presione 4: ");
   
    printf("\n\n Ingrese una opcion: ");
    scanf("%d",&opcion);
    printf("\n");
   
    if(opcion>3)
    {
      printf("\n Opcion NO VALIDA concentrese porfavor");
      printf("\n\n ** PRESIONE CUALQUIER TECLA PARA VOLVER AL MENU **");
      getch();
    }
   
    switch(opcion)
    {
        case 1:
        insertar_colas();
        break;
       
        case 2:
        imprimir_colas();
        break;
       
        case 3:
        exit(0);
    }
  }
  while(opcion!=0);
  getch();
}

void insertar_colas()
{
  printf("\n\n Ingrese numero: ");
  scanf("%d",&fono);
  printf("\n Ingrese duracion:");
  scanf("%d",&tiempo);
  act_1=(nodoc*)malloc(sizeof(nodoc));
  act_1->dato_colas=fono;
  act_1->dura_colas=tiempo;
  act_1->sgte=NULL;
 
  if(fin==NULL)
    fin=inicio_1=act_1;
  else
  {
    fin->sgte=act_1;
    fin=act_1;
  }
}

}
void imprimir_colas()
{
  act_1=inicio_1;
  while(act_1!=NULL)
  {
    printf(" La llamada %d duro : %d min\n",act_1->dato_colas,act_1->dura_colas);
    act_1=act_1->sgte;
  }
  printf("\n\n ** PRESIONE CUALQUIER TECLA PARA VOLVER AL MENU **");
  getch();
}


http://c.conclase.net/edd/?cap=003