pila
y de co
la se deriva fácilmente del de lista enlazada. Según se ha podido observar, en una lista enlazada es posible añadir información de manera muy flexible. Concretamente, se puede añadir o eliminar información:
P)oner Q)uitar V)er B)orrar H)Ayuda S)alir
listaenlazada.h
y
listaenlazada.c
). Hacemos esto para reducir al mínimo el tamaño del programa, auqnue basta con descartar las opciones y funciones innecesarias en
main.c
(sin modificar
listaenlazada.h
ni
listaenlazada.c
). El resultado final es el programa que puede verse en la sección siguiente.listaenlazada.h |
#ifndef __LISTAENLAZADA__ #define __LISTAENLAZADA__ /* Esta declaración de nodo es la más sencilla posible. En una aplicación real el nodo contendrá muchos más campos, como corresponde a un registro de una base de datos. */ typedef struct Nodo { int valor; struct Nodo * sig; } Nodo; typedef struct Lista { Nodo * ppio; Nodo * fin; } Lista; void leer_nodo(Nodo *); void escribir_nodo(Nodo *); void insertar_ppio(Lista * pl); void insertar_final(Lista * pl); void insertar_ordenado(Lista * pl); void borrar_principio(Lista * pl); void borrar_final(Lista * pl); void borrar_buscando(Lista * pl); void ver_lista(Lista * pl); void borrar_lista(Lista * pl); void duplicar_lista(Lista * pl); #endif |
main.h |
#ifndef __PROGRAMAPRINCIPAL__ #define __PROGRAMAPRINCIPAL__ typedef struct Global { Lista * lista; } Global; typedef void (*pfuncion)(Global *); void dispatcher( char * pm, char * ov[], struct Global * pg, pfuncion pf[]); void iniciacion(Global * pg, int argc, char * argv[]); void terminacion(Global * pg); void ayuda(Global * pg); void opcion_1(Global * pg); void opcion_4(Global * pg); void opcion_7(Global * pg); void opcion_8(Global * pg); void salir(Global * pg); void volver(Global * pg); #endif |
main.c |
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<ctype.h> #include "utiles.h" #include "listaenlazada.h" #include "main.h" int main(int argc, char * argv[]) { Global * pg = (Global *)malloc(sizeof(Global)); pfuncion pfun[] = { &opcion_1, /* Ojo : orden de funciones */ &opcion_4, /* igual a orden de opciones válidas */ &opcion_7, &opcion_8, &ayuda, /* "H" */ &salir, /* "S" */ NULL }; char * opcionesvalidas[] = { "1", /* Ojo al orden de opciones */ "4", "7", "8", "H", "S" }; /* El menú de pila se reduce a cuatro opciones, más las ya habituales opciones de Ayuda y de Salida. */ char * menu = "PILAS\n\n\ • 1.- Poner (push).\n\ • 4.- Quitar (pop).\n\ • 7.- Ver toda la pila.\n\ • 8.- Borrar toda la pila.\n\ • H.- Ayuda.\n\ • S.- Salir."; iniciacion(pg, argc, argv); dispatcher( menu, opcionesvalidas, pg, pfun); terminacion(pg); puts("\n\nThat's all folks!\n"); return 0; } /* Todas las opciones residen en listaenlazada.c */ void dispatcher( char * pm, char * ov[], Global * pg, pfuncion pf[]) { char * temp = NULL; /* Para leer la instrucción */ int instruccion; /* dada por el usuario */ int num_opciones = 0; int i; /* Recuento de opciones */ while(pf[num_opciones] != NULL) num_opciones++; /* Bucle principal de ejecución */ do { printf("%s ", pm); temp = sgets(); instruccion = -1; /* Ahora se busca la instrucción dada entre las posibles instrucciones válidas. De este modo se halla el número de instrucción solicitado, que servirá como índice de función. Si no se encuentra la instrucción, el índice no es válido y se llama a volver, que no hace nada, y siempre es la última opción. */ for(i=0;i<num_opciones;i++)/* Ojo a las instrucciones vacías */ if(0==strcasecmp(ov[i],temp)) { instruccion = i; break; } system(BORRAR); if (-1 != instruccion) pf[instruccion](pg); else printf("%c", 7); free(temp); temp = NULL; } while (&salir != pf[instruccion]); } /* Fin de dispatcher() */ void iniciacion(Global * pg, int argc, char * argv[]) { pg->lista = malloc(sizeof(Lista)); pg->lista->ppio = NULL; /* Al comenzar NO hay nodos */ pg->lista->fin = NULL; /* Al comenzar NO hay nodos */ } void terminacion(Global * pg) { borrar_lista(pg->lista); /* Aunque no es preciso, liberamos todos los nodos de la lista. En una base de datos, sería preciso ofrecer la opción de guardar la información en disco. */ } void volver(struct Global * pg) { return; } void ayuda(Global * pg) { /* Vamos a mostrar los valores y direcciones de todas las variables (y nodos) del programa.*/ Nodo * temp; Lista * pl = pg->lista; printf("\n\nProceso de ayuda.\n\n"); printf("\n\npg vale : $%p\n", pg); printf("pl->ppio vale : $%p\n", pl->ppio); printf("pl->fin vale : $%p\n", pl->fin); if (NULL == pl->ppio) { /* La lista está vacía */ printf("\n\nLa lista está vacía.\n\n"); } else { printf("\n\nContenido de la lista (izquierda primero).\n\n"); temp = pl->ppio; do { printf("Dir. nodo: $%p - Valor almacenado: %d - Dir. nodo siguiente: $%p\n", temp, temp->valor,temp->sig); temp = temp->sig; } while (temp); /* En el último elemento, el campo sig es cero */ printf("\n\n"); } } void salir(Global * pg) { /* Si hubiera cambios que guardar, este sería el lugar */ return; } void opcion_1(Global * pg) { insertar_ppio(pg->lista); } void opcion_4(Global * pg) { borrar_principio(pg->lista); } void opcion_7(Global * pg) { ver_lista(pg->lista); } void opcion_8(Global * pg) { borrar_lista(pg->lista); } |
listaenlazada.c |
#include <stdlib.h> #include "utiles.h" #include "listaenlazada.h" void leer_nodo(Nodo * pn) { char * temp; temp = pedir("\n\nEscriba el número entero que se\ almacenará en este nodo:\n\n"); pn->valor = strtol(temp,0,10); /* Liberamos temp para que no haya fugas de memoria */ free(temp); pn->sig = NULL; /* Por seguridad */ printf("\n"); } void escribir_nodo(Nodo * pn) { printf("%6d", pn->valor); } /* • 1.- Insertar nodo al principio. */ void insertar_ppio(Lista * pl) { Nodo * temp; temp = (Nodo *)malloc(sizeof(Nodo)); if (temp!=NULL) /* Hay espacio para el nodo nuevo */ { printf("\n\nAdición de un nodo al principio de la lista.\n\n"); leer_nodo(temp); if (NULL == pl->ppio) { /* La lista estaba vacía y pasa a tener un solo nodo. Tanto ppio como fin apuntan a ese nodo. El elemento siguiente no existe, luego se da al puntero sig el valor NULL. */ pl->ppio = temp; pl->fin = temp; pl->ppio->sig = NULL; } else { /* La lista no está vacía. El nodo recién creado pasa a ocupar la primera posición. Si hay un sólo nodo, pasamos a tener dos, y el puntero de fin ya tiene valor correcto. Si había dos o más nodos, pasamos a tener tres o más nodos, y el puntero de fin también tiene valor correcto. */ temp->sig = pl->ppio; pl->ppio = temp; /* El nodo pasa a ser la nueva ppio*/ } } else printf("\n\nSALIENDO- No hay espacio para añadir un nodo al principio.\n\n"); } /* • 2.- Insertar nodo al final. */ void insertar_final(Lista * pl) { Nodo * temp; temp = (Nodo *)malloc(sizeof(Nodo)); if (temp!=NULL) { printf("\n\nAdición de un nodo al final de la lista.\n\n"); leer_nodo(temp); if (NULL == pl->ppio) { /* La lista estaba vacía y pasa a tener un solo nodo. Tanto ppio como fin apuntan a ese nodo. El elemento siguiente no existe, luego se da al puntero sig el valor 0. */ pl->ppio = temp; pl->fin = temp; pl->ppio->sig = NULL; } else { /* La lista no está vacía. El nodo recién creado pasa a ocupar la última posición */ pl->fin->sig = temp; pl->fin = temp; /* El nodo pasa a ser el nuevo fin*/ temp->sig = NULL; /* No hay un siguiente del último elemento */ } } else printf("\n\nSALIENDO- No hay espacio para añadir un nodo al final."); } /* • 3.- Insertar nodo buscando su posición. */ void insertar_ordenado(Lista * pl) { Nodo * temp, *anterior, *posterior; temp = (Nodo *)malloc(sizeof(Nodo)); if (temp) { printf("\n\nInserción de un nodo buscando su posición.\n\n"); leer_nodo(temp); if (NULL == pl->ppio) { /* La lista estaba vacía y pasa a tener un solo nodo. Tanto ppio como fin apuntan a ese nodo. El elemento siguiente no existe, luego se da al puntero sig el valor 0. */ pl->ppio = temp; pl->fin = temp; pl->ppio->sig = 0; } else { /* La lista no está vacía. El nodo recién creado debe ocupar una posición dada por su valor. Suponemos que la lista está ordenada de modo ascendente (el nodo de valor más pequeño está a la izquierda del todo). Por tanto, primero se verifica si el valor del nodo recién leído es anterior al valor situado en la ppio; de ser así, se pone nuestro nodo como ppio. Si nuestro nodo no es anterior a la ppio, quizá esté por detrás de la fin (a la derecha del todo). Si es así, se pone al final del todo. Por último, si no está ni antes que la ppio ni después de la fin, ocupa una posición intermedia. Esa posición se busca, y se inserta el nodo adecuadamente. */ /* Veamos si está antes del principio */ if (temp->valor <= pl->ppio->valor) { temp->sig = pl->ppio; pl->ppio = temp; } else /* Veamos si está despues del final */ if (temp->valor >= pl->fin->valor) { pl->fin->sig = temp; pl->fin = temp; pl->fin->sig = NULL; } else /* Busquemos su posición-como mínimo hay dos nodos en la lista */ { /* Para que el nodo esté en posición correcta, su valor debe ser mayor o igual que el del nodo de su izquierda, (anterior)y menor o igual que el valor del nodo de su derecha (posterior)*/ anterior = pl->ppio; posterior = pl->ppio->sig; while(!(temp->valor >= anterior->valor && temp->valor <= posterior->valor)) { anterior = posterior; posterior = posterior->sig; } /* Al llegar aquí, hay que insertar temp entre anterior y posterior */ temp->sig = posterior; anterior->sig = temp; } } } else printf("\n\nSALIENDO- No hay espacio para añadir un nodo al principio."); } /* • 4.- Borrar nodo al principio. */ void borrar_principio(Lista * pl) { Nodo * temp; if (NULL == pl->ppio) printf("\n\nLa lista está vacía.\n\n"); else { if (NULL != pl->ppio->sig) /* No es el único nodo */ { temp = pl->ppio; pl->ppio = pl->ppio->sig; free(temp); } else /* Es el último nodo */ { free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } } printf("\n\nNodo inicial borrado.\n\n"); } /* • 5.- Borrar nodo al final. */ void borrar_final(Lista * pl) { Nodo * temp; if (NULL == pl->ppio) printf("\n\nLa lista está vacía.\n\n"); else { if (NULL == pl->ppio->sig) /* Hay un solo nodo */ { printf("\n\nEl valor del nodo borrado es: "); escribir_nodo(pl->ppio); free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } else { /* Hay que buscar el nodo anterior al final */ temp = pl->ppio; while (temp->sig != pl->fin) { temp = temp->sig; } /* Al llegar aquí, temp apunta al nodo anterior a fin */ printf("\n\nEl valor del nodo borrado es: "); escribir_nodo(pl->fin); printf("\n"); free(pl->fin); pl->fin = temp; temp->sig = NULL; } } printf("\n\nNodo final borrado.\n\n"); } /* • 6.- Borrar un nodo tras buscarlo. */ void borrar_buscando(Lista * pl) { /* Se trata de tomar un valor y buscarlo en la lista. Si se encuentra en algún nodo, se elimina ese nodo. Si no se encuentra en ningún nodo, se advierte al usuario. Este sería el mecanismo necesario para quitar una tarea de una cola, por ejemplo la de impresión. */ int buscado; Nodo *temp, *indice, *anterior; if (NULL == pl->ppio) { printf("\n\nPerdón, la lista está vacía.\n\n"); return; } printf("\n\nEscriba el valor que quiere borrar: "); scanf("%d%*c", &buscado); if (pl->ppio == pl->fin) /* Hay un solo nodo */ { if (buscado == pl->ppio->valor) { free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } else printf("No se encontró el valor."); } else /*Hay dos nodos o más */ { if (buscado == pl->ppio->valor) { temp = pl->ppio; pl->ppio = pl->ppio->sig; free(temp); } else if (buscado == pl->fin->valor) { indice = pl->ppio; while(indice->sig != pl->fin) { indice = indice->sig; } free(pl->fin); pl->fin = indice; pl->fin->sig=NULL; } else /*Puede estar en posición intermedia; no es el primero ni el último */ { anterior = pl->ppio; for(indice=anterior->sig;indice!=pl->fin;indice=indice->sig) { if (buscado == indice->valor) { anterior->sig = indice->sig; free(indice); return; } anterior = anterior->sig; } if (indice == pl->fin) printf("No se encontró el valor."); } } } /* • 7.- Ver toda la lista. */ void ver_lista(Lista * pl) { Nodo * temp; if (NULL == pl->ppio) { /* La lista está vacía */ printf("\n\nPerdón, la lista está vacía.\n\n"); } else { printf("\n\nContenido de la lista (izquierda primero).\n\n"); temp = pl->ppio; do { escribir_nodo(temp); temp = temp->sig; } while (NULL != temp); /* En el último elemento, el campo sig es cero */ printf("\n\n"); } } /* • 8.- Borrar toda la lista. */ void borrar_lista(Lista * pl) { /* No hay otro remedio que ir hasta el penúltimo elemento, borrarlo, y repetir el proceso de ir al penúltimo elemento hasta que no queden nodos. Si construyésemos una lista formada por nodos con dos enlaces, uno hacia la derecha y otro hacia la izquierda... (véanse las listas doblemente enlazadas) */ Nodo *temp, *penultimo; if (NULL == pl->ppio) { /* La lista está vacía */ printf("\n\nPerdón, la lista está vacía.\n\n"); } else { if(NULL == pl->ppio->sig) { /* Hay un solo elemento */ free(pl->ppio); pl->ppio = 0; pl->fin = 0; } else { do { penultimo = pl->ppio; temp = pl->ppio->sig; while(NULL != temp->sig) { penultimo = temp; temp = temp->sig; } free(temp); penultimo->sig = NULL; } while (penultimo != pl->ppio); free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } printf("\n\nLa lista se ha borrado.\n\n"); } } /* • 9.- Duplicar una lista. */ void duplicar_lista(Lista * pl) { Lista * lista_local; /* Para manejar la otra lista */ Nodo * tg,*tl; if (NULL == pl->ppio) { printf("\n\nImposible duplicar - lista vacía.\n\n"); } else { lista_local = malloc(sizeof(Lista)); tg = pl->ppio; tl = (Nodo *)malloc(sizeof(Nodo)); tl->valor = tg->valor; tl->sig = NULL; lista_local->ppio = tl; lista_local->fin = tl; tg = tg->sig; while (tg) { tl = (Nodo *)malloc(sizeof(Nodo)); tl->valor = tg->valor; tl->sig = 0; lista_local->fin->sig = tl; lista_local->fin = tl; tg=tg->sig; } /* Ya tenemos toda la lista copiada. Vamos a verificarlo llamando a una de las opciones y pasándole el nuevo parámetro (local)*/ printf("\n\nLISTA LOCAL - "); ver_lista(lista_local); /* Y después borramos la lista */ borrar_lista(lista_local); free(lista_local); } } |
makefile |
OBJECTS = main.o utiles.o listaenlazada.o pila: $(OBJECTS) cc $(OBJECTS) -o pila utiles.o: utiles.c utiles.h cc -c utiles.c -o utiles.o main.o: main.c utiles.h main.h cc -c main.c listaenlazada.o: listaenlazada.c listaenlazada.h cc -c listaenlazada.c clean: rm -f utiles.o rm -f *.o rm -f pila |
listaenlazada.c
como biblioteca independiente, que es nuestro objetivo. Por tanto, vamos a rediseñar
listaenlazada.c
(básicamente se trata de cambiar los nombres de sus opciones) y
main.c
(haciendo que
opcion_i
sea una función intermedia que llama a los elementos necesarios de
listaenlazada.c
). De este modo
listaenlazada.c
se desacopla por completo de
main.c
, y el programa núcleo se hace más flexible. Estamos facilitando de este modo el uso de bibliotecas.makefile |
OBJECTS = main.o utiles.o listaenlazada.o cola: $(OBJECTS) cc $(OBJECTS) -o cola utiles.o: utiles.c utiles.h cc -c utiles.c -o utiles.o main.o: main.c utiles.h main.h cc -c main.c listaenlazada.o: listaenlazada.c listaenlazada.h cc -c listaenlazada.c clean: rm -f utiles.o rm -f *.o rm -f cola |
listaenlazada.h |
#ifndef __LISTAENLAZADA__ #define __LISTAENLAZADA__ /* Esta declaración de nodo es la más sencilla posible. En una aplicación real el nodo contendrá muchos más campos, como corresponde a un registro de una base de datos. */ typedef struct Nodo { int valor; struct Nodo * sig; } Nodo; typedef struct Lista { Nodo * ppio; Nodo * fin; } Lista; void leer_nodo(Nodo *); void escribir_nodo(Nodo *); void insertar_ppio(Lista * pl); void insertar_final(Lista * pl); void insertar_ordenado(Lista * pl); void borrar_principio(Lista * pl); void borrar_final(Lista * pl); void borrar_buscando(Lista * pl); void ver_lista(Lista * pl); void borrar_lista(Lista * pl); void duplicar_lista(Lista * pl); #endif |
listaenlazada.c |
#include <stdlib.h> #include "utiles.h" #include "listaenlazada.h" void leer_nodo(Nodo * pn) { char * temp; temp = pedir("\n\nEscriba el número entero que se\ almacenará en este nodo:\n\n"); pn->valor = strtol(temp,0,10); /* Liberamos temp para que no haya fugas de memoria */ free(temp); pn->sig = NULL; /* Por seguridad */ printf("\n"); } void escribir_nodo(Nodo * pn) { printf("%6d", pn->valor); } /* • 1.- Insertar nodo al principio. */ void insertar_ppio(Lista * pl) { Nodo * temp; temp = (Nodo *)malloc(sizeof(Nodo)); if (temp!=NULL) /* Hay espacio para el nodo nuevo */ { printf("\n\nAdición de un nodo al principio de la lista.\n\n"); leer_nodo(temp); if (NULL == pl->ppio) { /* La lista estaba vacía y pasa a tener un solo nodo. Tanto ppio como fin apuntan a ese nodo. El elemento siguiente no existe, luego se da al puntero sig el valor NULL. */ pl->ppio = temp; pl->fin = temp; pl->ppio->sig = NULL; } else { /* La lista no está vacía. El nodo recién creado pasa a ocupar la primera posición. Si hay un sólo nodo, pasamos a tener dos, y el puntero de fin ya tiene valor correcto. Si había dos o más nodos, pasamos a tener tres o más nodos, y el puntero de fin también tiene valor correcto. */ temp->sig = pl->ppio; pl->ppio = temp; /* El nodo pasa a ser la nueva ppio*/ } } else printf("\n\nSALIENDO- No hay espacio para añadir un nodo al principio.\n\n"); } /* • 2.- Insertar nodo al final. */ void insertar_final(Lista * pl) { Nodo * temp; temp = (Nodo *)malloc(sizeof(Nodo)); if (temp!=NULL) { printf("\n\nAdición de un nodo al final de la lista.\n\n"); leer_nodo(temp); if (NULL == pl->ppio) { /* La lista estaba vacía y pasa a tener un solo nodo. Tanto ppio como fin apuntan a ese nodo. El elemento siguiente no existe, luego se da al puntero sig el valor 0. */ pl->ppio = temp; pl->fin = temp; pl->ppio->sig = NULL; } else { /* La lista no está vacía. El nodo recién creado pasa a ocupar la última posición */ pl->fin->sig = temp; pl->fin = temp; /* El nodo pasa a ser el nuevo fin*/ temp->sig = NULL; /* No hay un siguiente del último elemento */ } } else printf("\n\nSALIENDO- No hay espacio para añadir un nodo al final."); } /* • 3.- Insertar nodo buscando su posición. */ void insertar_ordenado(Lista * pl) { Nodo * temp, *anterior, *posterior; temp = (Nodo *)malloc(sizeof(Nodo)); if (temp) { printf("\n\nInserción de un nodo buscando su posición.\n\n"); leer_nodo(temp); if (NULL == pl->ppio) { /* La lista estaba vacía y pasa a tener un solo nodo. Tanto ppio como fin apuntan a ese nodo. El elemento siguiente no existe, luego se da al puntero sig el valor 0. */ pl->ppio = temp; pl->fin = temp; pl->ppio->sig = 0; } else { /* La lista no está vacía. El nodo recién creado debe ocupar una posición dada por su valor. Suponemos que la lista está ordenada de modo ascendente (el nodo de valor más pequeño está a la izquierda del todo). Por tanto, primero se verifica si el valor del nodo recién leído es anterior al valor situado en la ppio; de ser así, se pone nuestro nodo como ppio. Si nuestro nodo no es anterior a la ppio, quizá esté por detrás de la fin (a la derecha del todo). Si es así, se pone al final del todo. Por último, si no está ni antes que la ppio ni después de la fin, ocupa una posición intermedia. Esa posición se busca, y se inserta el nodo adecuadamente. */ /* Veamos si está antes del principio */ if (temp->valor <= pl->ppio->valor) { temp->sig = pl->ppio; pl->ppio = temp; } else /* Veamos si está despues del final */ if (temp->valor >= pl->fin->valor) { pl->fin->sig = temp; pl->fin = temp; pl->fin->sig = NULL; } else /* Busquemos su posición-como mínimo hay dos nodos en la lista */ { /* Para que el nodo esté en posición correcta, su valor debe ser mayor o igual que el del nodo de su izquierda, (anterior)y menor o igual que el valor del nodo de su derecha (posterior)*/ anterior = pl->ppio; posterior = pl->ppio->sig; while(!(temp->valor >= anterior->valor && temp->valor <= posterior->valor)) { anterior = posterior; posterior = posterior->sig; } /* Al llegar aquí, hay que insertar temp entre anterior y posterior */ temp->sig = posterior; anterior->sig = temp; } } } else printf("\n\nSALIENDO- No hay espacio para añadir un nodo al principio."); } /* • 4.- Borrar nodo al principio. */ void borrar_principio(Lista * pl) { Nodo * temp; if (NULL == pl->ppio) printf("\n\nLa lista está vacía.\n\n"); else { if (NULL != pl->ppio->sig) /* No es el único nodo */ { temp = pl->ppio; pl->ppio = pl->ppio->sig; free(temp); } else /* Es el último nodo */ { free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } } printf("\n\nNodo inicial borrado.\n\n"); } /* • 5.- Borrar nodo al final. */ void borrar_final(Lista * pl) { Nodo * temp; if (NULL == pl->ppio) printf("\n\nLa lista está vacía.\n\n"); else { if (NULL == pl->ppio->sig) /* Hay un solo nodo */ { printf("\n\nEl valor del nodo borrado es: "); escribir_nodo(pl->ppio); free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } else { /* Hay que buscar el nodo anterior al final */ temp = pl->ppio; while (temp->sig != pl->fin) { temp = temp->sig; } /* Al llegar aquí, temp apunta al nodo anterior a fin */ printf("\n\nEl valor del nodo borrado es: "); escribir_nodo(pl->fin); printf("\n"); free(pl->fin); pl->fin = temp; temp->sig = NULL; } } printf("\n\nNodo final borrado.\n\n"); } /* • 6.- Borrar un nodo tras buscarlo. */ void borrar_buscando(Lista * pl) { /* Se trata de tomar un valor y buscarlo en la lista. Si se encuentra en algún nodo, se elimina ese nodo. Si no se encuentra en ningún nodo, se advierte al usuario. Este sería el mecanismo necesario para quitar una tarea de una cola, por ejemplo la de impresión. */ int buscado; Nodo *temp, *indice, *anterior; if (NULL == pl->ppio) { printf("\n\nPerdón, la lista está vacía.\n\n"); return; } printf("\n\nEscriba el valor que quiere borrar: "); scanf("%d%*c", &buscado); if (pl->ppio == pl->fin) /* Hay un solo nodo */ { if (buscado == pl->ppio->valor) { free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } else printf("No se encontró el valor."); } else /*Hay dos nodos o más */ { if (buscado == pl->ppio->valor) { temp = pl->ppio; pl->ppio = pl->ppio->sig; free(temp); } else if (buscado == pl->fin->valor) { indice = pl->ppio; while(indice->sig != pl->fin) { indice = indice->sig; } free(pl->fin); pl->fin = indice; pl->fin->sig=NULL; } else /*Puede estar en posición intermedia; no es el primero ni el último */ { anterior = pl->ppio; for(indice=anterior->sig;indice!=pl->fin;indice=indice->sig) { if (buscado == indice->valor) { anterior->sig = indice->sig; free(indice); return; } anterior = anterior->sig; } if (indice == pl->fin) printf("No se encontró el valor."); } } } /* • 7.- Ver toda la lista. */ void ver_lista(Lista * pl) { Nodo * temp; if (NULL == pl->ppio) { /* La lista está vacía */ printf("\n\nPerdón, la lista está vacía.\n\n"); } else { printf("\n\nContenido de la lista (izquierda primero).\n\n"); temp = pl->ppio; do { escribir_nodo(temp); temp = temp->sig; } while (NULL != temp); /* En el último elemento, el campo sig es cero */ printf("\n\n"); } } /* • 8.- Borrar toda la lista. */ void borrar_lista(Lista * pl) { /* No hay otro remedio que ir hasta el penúltimo elemento, borrarlo, y repetir el proceso de ir al penúltimo elemento hasta que no queden nodos. Si construyésemos una lista formada por nodos con dos enlaces, uno hacia la derecha y otro hacia la izquierda... (véanse las listas doblemente enlazadas) */ Nodo *temp, *penultimo; if (NULL == pl->ppio) { /* La lista está vacía */ printf("\n\nPerdón, la lista está vacía.\n\n"); } else { if(NULL == pl->ppio->sig) { /* Hay un solo elemento */ free(pl->ppio); pl->ppio = 0; pl->fin = 0; } else { do { penultimo = pl->ppio; temp = pl->ppio->sig; while(NULL != temp->sig) { penultimo = temp; temp = temp->sig; } free(temp); penultimo->sig = NULL; } while (penultimo != pl->ppio); free(pl->ppio); pl->ppio = NULL; pl->fin = NULL; } printf("\n\nLa lista se ha borrado.\n\n"); } } /* • 9.- Duplicar una lista. */ void duplicar_lista(Lista * pl) { Lista * lista_local; /* Para manejar la otra lista */ Nodo * tg,*tl; if (NULL == pl->ppio) { printf("\n\nImposible duplicar - lista vacía.\n\n"); } else { lista_local = malloc(sizeof(Lista)); tg = pl->ppio; tl = (Nodo *)malloc(sizeof(Nodo)); tl->valor = tg->valor; tl->sig = NULL; lista_local->ppio = tl; lista_local->fin = tl; tg = tg->sig; while (tg) { tl = (Nodo *)malloc(sizeof(Nodo)); tl->valor = tg->valor; tl->sig = 0; lista_local->fin->sig = tl; lista_local->fin = tl; tg=tg->sig; } /* Ya tenemos toda la lista copiada. Vamos a verificarlo llamando a una de las opciones y pasándole el nuevo parámetro (local)*/ printf("\n\nLISTA LOCAL - "); ver_lista(lista_local); /* Y después borramos la lista */ borrar_lista(lista_local); free(lista_local); } } |
main.h |
#ifndef __PROGRAMAPRINCIPAL__ #define __PROGRAMAPRINCIPAL__ typedef struct Global { Lista * lista; } Global; typedef void (*pfuncion)(Global *); void dispatcher( char * pm, char * ov[], struct Global * pg, pfuncion pf[]); void iniciacion(Global * pg, int argc, char * argv[]); void terminacion(Global * pg); void ayuda(Global * pg); void salir(Global * pg); void volver(Global * pg); /* No necesitamos las opciones 2, 3, 4, 6 y 9 */ void opcion_1(Global * pg); /* void opcion_2(Global * pg); void opcion_3(Global * pg); void opcion_4(Global * pg); */ void opcion_5(Global * pg); /* void opcion_6(Global * pg); */ void opcion_7(Global * pg); void opcion_8(Global * pg); /* void opcion_9(Global * pg); */ #endif |
main.c |
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<ctype.h> #include "utiles.h" #include "listaenlazada.h" #include "main.h" /* Implementación de una cola basada en una lista simplemente enlazada */ int main(int argc, char * argv[]) { Global * pg = (Global *)malloc(sizeof(Global)); pfuncion pfun[] = { &opcion_1, /* Ojo: el orden de funciones tiene que ser */ &opcion_5, /* igual al orden de opciones válidas */ &opcion_7, &opcion_8, &ayuda, /* "H" */ &salir, /* "S" */ NULL }; char * opcionesvalidas[] = { "1", /* Ojo: el orden de opciones tiene que */ "5", /* ser igual al orden de funciones */ "7", "8", "H", "S" }; char * menu = "Cola basada en una lista enlazada\n\n\ • 1.- Poner en cola (enqueue).\n\ • 5.- Quitar de cola (dequeue).\n\ • 7.- Ver toda la cola.\n\ • 8.- Borrar toda la cola.\n\ • H.- Ayuda.\n\ • S.- Salir."; iniciacion(pg, argc, argv); dispatcher( menu, opcionesvalidas, pg, pfun); terminacion(pg); puts("\n\nThat's all folks!\n"); return 0; } /* Hacemos uso de la biblioteca listaenlazada.c */ void dispatcher( char * pm, char * ov[], Global * pg, pfuncion pf[]) { char * temp = NULL; /* Para leer la instrucción */ int instruccion; /* dada por el usuario */ int num_opciones = 0; int i; /* Recuento de opciones */ while(pf[num_opciones] != NULL) num_opciones++; /* Bucle principal de ejecución */ do { printf("%s ", pm); temp = sgets(); instruccion = -1; /* Ahora se busca la instrucción dada entre las posibles instrucciones válidas. De este modo se halla el número de instrucción solicitado, que servirá como índice de función. Si no se encuentra la instrucción, el índice no es válido y se llama a volver, que no hace nada, y siempre es la última opción. */ for(i=0;i<num_opciones;i++)/* Ojo a las instrucciones vacías */ if(0==strcasecmp(ov[i],temp)) { instruccion = i; break; } system(BORRAR); if (-1 != instruccion) pf[instruccion](pg); else printf("%c", 7); free(temp); temp = NULL; } while (&salir != pf[instruccion]); } /* Fin de dispatcher() */ void iniciacion(Global * pg, int argc, char * argv[]) { pg->lista = malloc(sizeof(Lista)); pg->lista->ppio = NULL; /* Al comenzar NO hay nodos */ pg->lista->fin = NULL; /* Al comenzar NO hay nodos */ } void terminacion(Global * pg) { borrar_lista(pg->lista); /* Aunque no es preciso, liberamos todos los nodos de la lista. En una base de datos, sería preciso ofrecer la opción de guardar la información en disco. */ } void volver(struct Global * pg) { return; } void ayuda(Global * pg) { /* Vamos a mostrar los valores y direcciones de todas las variables (y nodos) del programa.*/ Nodo * temp; Lista * pl = pg->lista; printf("\n\nProceso de ayuda.\n\n"); printf("\n\npg vale : $%p\n", pg); printf("pl->ppio vale : $%p\n", pl->ppio); printf("pl->fin vale : $%p\n", pl->fin); if (NULL == pl->ppio) { /* La lista está vacía */ printf("\n\nLa cola está vacía.\n\n"); } else { printf("\n\nContenido de la cola (izquierda primero).\n\n"); temp = pl->ppio; do { printf("Dir. nodo: $%p - Valor almacenado: %d - Dir. nodo siguiente: $%p\n", temp, temp->valor,temp->sig); temp = temp->sig; } while (temp); /* En el último elemento, el campo sig es cero */ printf("\n\n"); } } void salir(Global * pg) { /* Si hubiera cambios que guardar, este sería el lugar */ return; } /* Solo necesitamos las opciones 1, 5, 7, 8, Ayuda y Salir */ void opcion_1(Global * pg) { insertar_ppio(pg->lista); } void opcion_5(Global * pg) { borrar_final(pg->lista); } void opcion_7(Global * pg) { ver_lista(pg->lista); } void opcion_8(Global * pg) { borrar_lista(pg->lista); } |
listaenlazada.c
es un ejemplo de lo que deben ser las bibliotecas construidas por el programador con vistas a su reutilización posterior. Las funciones y estructuras de datos construidas son independientes del exterior (salvo el uso de
utiles.c
). En particular,
listaenlazada.c
es independiente de esta versión del programa núcleo, y se puede utilizar en cualquier otro programa sin más dificultad que modificar la estructura de datos
Nodo
, y las funciones
leer_nodo()
y
escribir_nodo()
. Sería sencillo añadir un iterador llamado
pasivar()
y otro llamado
activar()
, que grabarían y leerían, respectivamente, toda la lista en disco. De este modo tenemos una herramienta flexible para el almacenamiento de cantidades casi arbitrarias de información.