Listas doblemente enlazadas en C: ejemplos, código completo…
El objetivo de este artículo es comprender las listas doblemente enlazadas y entender sus diferencias con las listas simples. Estas suelen utilizarse en programación cuando se requieren múltiples operaciones de inserción o eliminación de elementos. A continuación, veremos algunos ejemplos.
¿Cuáles son los requisitos?
Los requisitos previos son el conocimiento de los tipos de datos, estructuras, el uso de typedef, los punteros, las funciones usuario y las listas enlazadas simples.
¿Qué son las listas doblemente enlazadas?
Las listas doblemente enlazadas son estructuras de datos semejantes a las listas enlazadas simples, pero algo más complejas. La asignación de memoria se realiza en el momento de la ejecución. En cambio, en relación a la listas enlazadas simples el enlace entre los elementos se hace gracias a dos punteros (uno que apunta hacia el elemento anterior y otro que apunta hacia el elemento siguiente):
- El puntero anterior del primer elemento debe apuntar hacia NULL (el inicio de la lista).
- El puntero siguiente del último elemento debe apuntar hacia NULL (el fin de la lista).
Para acceder a un elemento, la lista puede ser recorrida en ambos sentidos: comenzando por el inicio, el puntero siguiente permite el desplazamiento hacia el próximo elemento; comenzando por el final, el puntero anterior permite el desplazamiento hacia el elemento anterior.
Resumiendo: el desplazamiento se hace en ambas direcciones, del primer al último elemento y/o del último al primer elemento.
¿Cómo se construye el modelo de un elemento de la lista?
Para definir un elemento de la lista será utilizado el tipo struct. El elemento de la lista contendrá un campo dato, un puntero anterior y un puntero siguiente.
Los punteros anterior y siguiente deben ser del mismo tipo que el elemento, de lo contrario no van a poder apuntar hacia un elemento de la lista. El puntero anterior permitirá el acceso hacia el elemento anterior mientras que el puntero siguiente permitirá el acceso hacia el próximo elemento:
typedef struct dl_ElementoLista { char *dato; struct dl_ElementoLista *anterior; struct dl_ElementoLista *siguiente; }dl_Elemento;
Para tener el control de la lista es preferible conservar algunos elementos: el primer elemento, el último elemento y el número de elementos.
Para esto, será utilizada otra estructura (no es obligatorio, pueden ser utilizadas variables):
typedef struct dl_ListaIdentificacion { dl_Elemento *inicio; dl_Elemento *fin; int tamaño; }dl_Lista;
El puntero inicio contendrá la dirección del primer elemento de la lista. El puntero fin va a contener la dirección del último elemento de la lista. La variable tamaño contendrá el número de elementos.
En cualquier posición de la lista, los punteros inicio y fin apuntan siempre al primer y último elemento. El campo tamaño va a contener el número de elementos de la lista cualquiera que sea la operación efectuada sobre la lista.
¿Qué operaciones sobre la lista doblemente enlazadas existen?
Para la inserción y la eliminación, una sola función bastará si está bien concebida en función de las necesidades. Debe recordarse que este artículo es puramente didáctico. Por esta razón se ha escrito una función para cada operación de inserción y eliminación.
Inicialización
Modelo de la función:
void inicialización (Lista *lista);
Esta operación tiene que ser realizada antes de otra operación sobre la lista. Esta empezará indicando el puntero inicio y también el puntero fin con el puntero NULL y, además, el tamaño con el valor 0.
La función:
void inicialización (Liste *liste){ lista->inicio = NULL; lista->fin = NULL; tamaño = 0; }
Inserción de un elemento en la lista
El siguiente es el algoritmo de inserción y el registro de los elementos: declaración del elemento que se insertará, asignación de la memoria para el nuevo elemento, completar el contenido del campo de datos, actualizar los punteros hacia el elemento anterior y el elemento siguiente, actualizar los punteros hacia el primero y último elemento si es necesario. Caso específico: en una lista con un solo elemento, el primero es al mismo tiempo el último. Actualizar el tamaño de la lista.
Para añadir un elemento a la lista hay varias situaciones: insertar en una lista vacía, al inicio de la lista, al final de la lista, antes de un elemento y después de un elemento.
Insertar en una lista vacía
Modelo de la función:
int ins_en_lista_vacia (dl_Lista *lista, char *dato);
La función en caso de error da como resultado -1, si no devuelve 0.
Las etapas son las siguientes: asignación de memoria para el nuevo elemento, llenado del campo de datos del nuevo elemento, el puntero anterior del nuevo elemento apuntará hacia NULL (dado que la inserción es hecha en una lista vacía utilizamos la dirección del puntero inicio que vale NULL), el puntero siguiente del nuevo elemento apuntará hacia NULL (debido a que la inserción es hecha en una lista vacía se utiliza la dirección del puntero fin que vale NULL), los punteros de inicio y fin señalarán hacia el nuevo elemento y el tamaño es actualizado:
La función:
int insercion_en_lista_vacia (dl_Lista * lista, char *dato){ dl_Elemento *nuevo_elemento; if ((nuevo_elemento = alloc (nuevo_elemento)) == NULL) return -1; strcpy (nuevo_elemento->dato, dato); nuevo_elemento->anterior = lista->inicio; nuevo_elemento->siguiente = lista->fin; lista->inicio = nuevo_elemento; lista->fin = nuevo_elemento; lista->tamaño++; return 0; }
Inserción al inicio de la lista
Modelo de la función:
int ins_inicio_lista(dl_Lista * lista, char *dato);
La función devuelve como resultado -1 en caso de error. En caso contrario, devuelve 0.
Las etapas son las siguientes: asignación de memoria al nuevo elemento, rellenado del campo de datos del nuevo elemento, el puntero anterior del nuevo elemento apunta hacia NULL, el puntero siguiente del nuevo elemento apuntará hacia el primero de los elementos, el puntero anterior del primer elemento apunta hacia el nuevo elemento, el puntero inicio apunta hacia el nuevo elemento, el puntero fin no cambia y el tamaño es incrementado:
La función:
int ins_inicio_lista(dl_Lista * lista, char *dato){ dl_Elemento *nuevo_elemento; if ((nuevo_elemento = alloc (nuevo_elemento)) == NULL) return -1; strcpy (nuevo_elemento->dato, dato); nuevo_elemento->anterior = NULL; nuevo_elemento->siguiente = lista->inicio; lista->inicio->anterior = nuevo_elemento; lista->inicio = nuevo_elemento; lista->tamaño++; return 0; }
Inserción al final de la lista
Modelo de la función:
int ins_fin_lista(dl_Lista * lista, char *dato);
La función devuelve el valor de -1 en caso de error, si no devuelve 0.
Las etapas son las siguientes: asignación de memoria al nuevo elemento, rellenado del campo de datos del nuevo elemento y el puntero siguiente del nuevo elemento va a apuntar hacia NULL<bold>, el puntero <bold>anterior del nuevo elemento apunta hacia el último elemento (es el puntero fin que contiene por ahora su dirección), el puntero siguiente del último elemento va a apuntar al nuevo elemento, el puntero fin apunta hacia el nuevo elemento, el puntero inicio no cambia y el tamaño es incrementado:
La función:
int ins_fin_lista(dl_Lista * lista, char *dato){ dl_Elemento *nuevo_elemento; if ((nuevo_elemento = alloc (nuevo_elemento)) == NULL) return -1; strcpy (nuevo_elemento->dato, dato); nuevo_elemento->siguiente = NULL; nuevo_elemento->anterior = lista->fin; lista->fin->siguiente = nuevo_elemento; lista->fin = nuevo_elemento; lista->tamaño++; return 0; }
Inserción antes de un elemento de la lista
Modelo de la función:
int ins_antes (dl_Lista * lista, char *dato, int pos);
La función da un -1 como resultado en caso de error, si no devuelve 0.
La inserción se efectuará antes de cierta posición pasado como argumento a la función. La posición indicada no debe ser ni el primer ni el último elemento. En ese caso hay que utilizar las funciones de inserción al inicio y/o al final de la lista.
Las etapas son las siguientes: asignación de memoria al nuevo elemento, rellenado del campo de datos del nuevo elemento, elección de una posición en la lista (la inserción se hará después de la posición elegida), el puntero siguiente del nuevo elemento apunta hacia el elemento actual, el puntero anterior del nuevo elemento apunta en la dirección hacia la que apunta el puntero anterior del elemento actual, el puntero siguiente del elemento que precede al elemento actual apuntará hacia el nuevo elemento, el puntero anterior del elemento actual apunta hacia el nuevo elemento, el puntero fin no cambia, el puntero inicio cambia si la posición elegida es la posición 1 y el tamaño se incrementa en una unidad:
La función:
int ins_antes (dl_Lista * lista, char *dato, int pos){ int i; dl_Elemento *nuevo_elemento, *actual; if ((nuevo_elemento = alloc (nuevo_elemento)) == NULL) return -1; strcpy (nuevo_elemento->dato, dato); actual = lista->inicio; for (i = 1; i < pos; ++i) actual = actual->siguiente; nuevo_elemento->siguiente = actual; nuevo_elemento-> anterior = actual->anterior; if(actual->anterior == NULL) lista->inicio = nuevo_elemento; else actual->anterior->siguiente = nuevo_elemento; actual->anterior = nuevo_elemento; lista->tamaño++; return 0; }
Inserción después de un elemento de la lista
Modelo de la función:
int ins_después (dl_Lista * lista, char *dato, int pos);
La función devuelve -1 en caso de error. De lo contrario devuelve 0. La inserción se efectuará después de que cierta posición haya pasado como argumento a la función. La posición indicada no debe ser el último elemento. En ese caso hay que utilizar la función de inserción al final de la lista.
Las etapas son las siguientes: asignación de memoria al nuevo elemento, rellenado del campo de datos del nuevo elemento, elección de una posición en la lista (la inserción se hará después de la posición elegida), el puntero siguiente del nuevo elemento apunta en la dirección del puntero siguiente del elemento actual (ver la imagen), el puntero anterior del nuevo elemento apunta hacia el elemento actual, el puntero anterior del elemento que va después del elemento actual apuntará hacia el nuevo elemento, el puntero siguiente del elemento actual apunta hacia el nuevo elemento, el puntero inicio no cambia, el puntero fin cambia si la posición elegida es la posición del último elemento (el tamaño de la lista) y el tamaño se incrementa en una unidad:
La función:
int ins_después (dl_Lista * lista, char *dato, int pos){ int i; dl_Elemento *nuevo_elemento, *actual; if ((nuevo_elemento = alloc (nuevo_elemento)) == NULL) return -1; strcpy (nuevo_elemento->dato, dato); actual = lista->inicio; for (i = 1; i < pos; ++i) actual = actual->siguiente; nuevo_elemento->siguiente = actual->siguiente; nuevo_elemento->anterior = actual; if(actual->siguiente == NULL) lista->fin = nuevo_elemento; else actual->siguiente->anterior = nuevo_elemento; actual->siguiente = nuevo_elemento; lista->tamaño++; return 0; }
Eliminación de un elemento de la lista
A continuación el algoritmo para eliminar un elemento de la lista: utilización de un puntero temporal para almacenar la dirección de los elementos a eliminar, el elemento a eliminar puede encontrarse en cualquier posición en la lista.
En relación a la lista enlazada simple en el que la eliminación sólo puede ser hecha después que un elemento ha sido designado, las listas doblemente enlazadas son más flexibles gracias a los 2 punteros que permiten guardar el rastro tanto hacia atrás como hacia delante. Luego hay que liberar la memoria ocupada por el elemento eliminado y actualizar el tamaño de la lista.
Para eliminar un elemento de la lista existen varias situaciones: eliminación al inicio de la lista, eliminación al final de la lista, eliminación antes de un elemento, eliminación después de un elemento.
Eliminación de un elemento
Sin embargo, la eliminación al inicio y al final de la lista doblemente enlazada así como antes o después de un elemento equivale a la eliminación en la posición 0 (cero) o en la posición N (N = número de elementos de la lista) o en otra parte de la lista.
En el caso de listas doblemente enlazadas la eliminación en cualquier posición no presenta ningún problema gracias a los punteros anterior y siguiente, que permiten conservar el enlace entre los elementos de la lista. Razón por la cual solo vamos a crear una función. Si deseamos eliminar el elemento al inicio de la lista elegiremos la posición cero, Si deseamos eliminar el elemento al final de la lista elegiremos la posición N (el número de elementos), si deseamos eliminar cualquier elemento entonces elegimos su posición en la lista.
Eliminación en la lista
Modelo de la función:
int supp(dl_Lista *lista, int pos);
La función entrega en caso de error un -1, si no devuelve 0.
Podemos distinguir varias situaciones: eliminación en la posición 1 en una lista con un solo elemento, eliminación en la posición 1 en una lista con varios elementos, eliminación en la última posición (el último elemento), eliminación en otra parte de la lista en cierta posición.
La eliminación en una lista vacía no tiene sentido.
Las etapas son las siguientes: la posición elegida es 1 (el caso de eliminación del primer elemento de la lista), el puntero sup_elemento va a contener la dirección del primer elemento, el puntero inicio contendrá la dirección contenida por el puntero siguiente del primero de los elemento que deseamos eliminar (si este puntero vale NULL entonces actualizamos el puntero fin ya que estamos en el caso de una lista con un solo elemento, si no hacemos apuntar el puntero anterior del 2do elemento hacia NULL):
La posición elegida es igual al número de elementos de la lista, el puntero sup_elemento contendrá la dirección del último elemento, hacemos apuntar al puntero siguiente del penúltimo elemento (es el elemento hacia el que apunta el puntero anterior del último elemento), hacia NULL y actualizamos el puntero fin:
La posición elegida es aleatoria en la lista, el puntero sup_elemento contendrá la dirección del elemento a eliminar, el puntero siguiente del elemento que antecede al elemento a eliminar apunta hacia la dirección contenida en el puntero siguiente del elemento a eliminar, el puntero anterior del elemento que va después del elemento a eliminar apunta hacia la dirección contenida en el puntero anterior del elemento a eliminar y el tamaño de la lista será disminuida en 1 elemento:
La función:
int supp(dl_Lista *lista, int pos){ int i; dl_Elemento *sup_elemento,*actual; if(lista->tamaño == 0) return -1; if(pos == 1){ /* eliminación del 1er elemento */ sup_elemento = lista->inicio; lista->inicio = lista->inicio->siguiente; if(lista->inicio == NULL) lista->fin = NULL; else lista->inicio->anterior == NULL; }else if(pos == lista->tamaño){ /* eliminación del último elemento */ sup_elemento = lista->fin; lista->fin->anterior->siguiente = NULL; lista->fin = lista->fin->anterior; }else { /* eliminación en otra parte */ actual = lista->inicio; for(i=1;i<pos;++i) actual = actual->siguiente; sup_elemento = actual; actual->anterior->siguiente = actual->siguiente; actual->siguiente->anterior = actual->anterior; } free(sup_elemento->dato); free(sup_elemento); lista->tamaño--; return 0; }
Visualización de la lista
Para mostrar la lista entera podemos posicionarnos al inicio o al final de la lista (el puntero inicio o fin lo permitirá). Luego utilizando el puntero siguiente o anterior de cada elemento, la lista es recorrida del 1er al último elemento o del último al 1er elemento. La condición para detener es dada por el puntero siguiente del último elemento que vale NULL en el caso de la lectura del inicio hacia el fin de la lista, o por el puntero anterior del 1er elemento que vale NULL, en el caso de una lectura del final hacia el inicio de la lista.
Las funciones:
void affiche(dl_Lista *lista){ /* visualización hacia adelante */ dl_Elemento *actual; actual = lista->inicio; /* punto de inicio el 1er elemento */ printf("[ "); while(actual != NULL){ printf("%s ",actual->dato); actual = actual->siguiente; } printf("]\n"); } void mustra_inv(dl_Lista *lista){ /* visualización hacia atrás */ dl_Elemento *actual; actual = lista->fin; /* punto de inicio el ultimo elemento */ printf("[ "); while(actual != NULL){ printf("%s : ",actual->dato); actual = actual->anterior; } printf("]\n"); }
Destrucción de la lista
Para destruir la lista entera, he utilizado la eliminación en la posición 1 ya que el tamaño es mayor a cero.
La función:
void destruir(dl_Lista *lista){ while(lista->tamaño > 0) sup(lista,1); }
¿Cómo sería un ejemplo completo de listas de enlace doble?
dlista.h
/* ---------- dlista.h ----------- */ typedef struct dl_ElementoLista { char *dato; struct dl_ElementoLista *anterior; struct dl_ElementoLista *siguiente; } dl_Elemento; typedef struct dl_Lista { dl_Elemento *inicio; dl_Elemento *fin; int tamaño; } dl_Lista; /* Inicialización de la lista */ void inicializar(dl_Lista *lista); // Inicializa una lista doblemente enlazada vacía dl_Elemento *asignar_memoria(dl_Elemento *nuevo_elemento); // Asigna memoria para un nuevo elemento de la lista /* Inserción */ int insertar_en_lista_vacia(dl_Lista *lista, char *dato); // Inserta un elemento en una lista vacía int insertar_al_inicio(dl_Lista *lista, char *dato); // Inserta un elemento al inicio de la lista int insertar_al_final(dl_Lista *lista, char *dato); // Inserta un elemento al final de la lista int insertar_después(dl_Lista *lista, char *dato, int pos); // Inserta un elemento después de una posición específica int insertar_antes(dl_Lista *lista, char *dato, int pos); // Inserta un elemento antes de una posición específica /* Eliminación */ int eliminar(dl_Lista *lista, int pos); // Elimina un elemento en una posición específica de la lista void mostrar(dl_Lista *lista); // Muestra los elementos de la lista en orden /**************************/ void mostrar_inversa(dl_Lista *lista); // Muestra los elementos de la lista en orden inverso void destruir (dl_Lista *lista); // Libera la memoria utilizada por la lista /* -------- FIN lista.h --------- */
dlista_function.h
/* ---------- dlista_function.h ----------- */ void inicialización(dl_Lista *lista) { lista->inicio = NULL; lista->fin = NULL; lista->tamaño = 0; } int inserción_en_lista_vacia(dl_Lista *lista, char *dato) { dl_Elemento *nuevo_elemento; if ((nuevo_elemento = alloc(nuevo_elemento)) == NULL) return -1; strcpy(nuevo_elemento->dato, dato); nuevo_elemento->anterior = NULL; nuevo_elemento->siguiente = NULL; lista->inicio = nuevo_elemento; lista->fin = nuevo_elemento; lista->tamaño++; return 0; } int ins_inicio_lista(dl_Lista *lista, char *dato) { dl_Elemento *nuevo_elemento; if ((nuevo_elemento = alloc(nuevo_elemento)) == NULL) return -1; strcpy(nuevo_elemento->dato, dato); nuevo_elemento->anterior = NULL; nuevo_elemento->siguiente = lista->inicio; lista->inicio->anterior = nuevo_elemento; lista->inicio = nuevo_elemento; lista->tamaño++; return 0; } int ins_fin_lista(dl_Lista *lista, char *dato) { dl_Elemento *nuevo_elemento; if ((nuevo_elemento = alloc(nuevo_elemento)) == NULL) return -1; strcpy(nuevo_elemento->dato, dato); nuevo_elemento->siguiente = NULL; nuevo_elemento->anterior = lista->fin; lista->fin->siguiente = nuevo_elemento; lista->fin = nuevo_elemento; lista->tamaño++; return 0; } int ins_después(dl_Lista *lista, char *dato, int pos) { int i; dl_Elemento *nuevo_elemento, *actual; if ((nuevo_elemento = alloc(nuevo_elemento)) == NULL) return -1; strcpy(nuevo_elemento->dato, dato); actual = lista->inicio; for (i = 1; i < pos; i++) actual = actual->siguiente; nuevo_elemento->siguiente = actual->siguiente; nuevo_elemento->anterior = actual; if (actual->siguiente == NULL) lista->fin = nuevo_elemento; else actual->siguiente->anterior = nuevo_elemento; actual->siguiente = nuevo_elemento; lista->tamaño++; return 0; } int ins_antes(dl_Lista *lista, char *dato, int pos) { int i; dl_Elemento *nuevo_elemento, *actual; if ((nuevo_elemento = alloc(nuevo_elemento)) == NULL) return -1; strcpy(nuevo_elemento->dato, dato); actual = lista->inicio; for (i = 1; i < pos; i++) actual = actual->siguiente; nuevo_elemento->siguiente = actual; nuevo_elemento->anterior = actual->anterior; if (actual->anterior == NULL) lista->inicio = nuevo_elemento; else actual->anterior->siguiente = nuevo_elemento; actual->anterior = nuevo_elemento; lista->tamaño++; return 0; } int sup(dl_Lista *lista, int pos) { int i; dl_Elemento *sup_elemento, *actual; if (lista->tamaño == 0) return -1; if (pos == 1) { /* eliminación de primer elemento */ sup_elemento = lista->inicio; lista->inicio = lista->inicio->siguiente; if (lista->inicio == NULL) lista->fin = NULL; else lista->inicio->anterior == NULL; } else if (pos == lista->tamaño) { /* eliminacion del ultimo elemento */ sup_elemento = lista->fin; lista->fin->anterior->siguiente = NULL; lista->fin = lista->fin->anterior; } else { /* eliminacion en otra parte */ actual = lista->inicio; for (i = 1; i < pos; i++) actual = actual->siguiente; sup_elemento = actual; actual->anterior->siguiente = actual->siguiente; actual->siguiente->anterior = actual->anterior; } free(sup_elemento->dato); free(sup_elemento); lista->tamaño--; return 0; } void destruir(dl_Lista *lista) { while (lista->tamaño > 0) supp(lista, 1); } dl_Elemento *alloc(dl_Elemento *nuevo_elemento) { if ((nuevo_elemento = (dl_Elemento *)malloc(sizeof(dl_Elemento))) == NULL) return NULL; if ((nuevo_elemento->dato = (char *)malloc(50 * sizeof(char))) == NULL) return NULL; return nuevo_elemento; } int menu(dl_Lista *lista) { int elección; if (lista->tamaño == 0) { printf("1. Adición del 1er elemento\n"); printf("2. Eliminar\n"); } else { printf("1. Añadir al inicio de la lista\n"); printf("2. Añadir al final de la lista\n"); printf("3. Añadir antes de la posición especificada\n"); printf("4. Añadir después de la posición especificada\n"); printf("5. Eliminacion en la posicion especificada\n"); printf("6. Destruir la lista\n"); printf("7. Eliminar\n"); } printf("\n\nElija: "); scanf("%d", &elección); getchar(); if (lista->tamaño == 0 && elección == 2) elección = 7; return elección; } int supp(dl_Lista *lista, int pos); void muestra(dl_Lista *lista) { dl_Elemento *actual; actual = lista->inicio; printf("[ "); while (actual != NULL) { printf("%s ", actual->dato); actual = actual->siguiente; } printf("]\n"); } void muestra_inv(dl_Lista *lista) { dl_Elemento *actual; actual = lista->fin; while (actual != NULL) { printf("%s : ", actual->dato); actual = actual->anterior; } printf("\n"); } /* -------- FIN dlista_function.h --------- */
dlista.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "dlista.h" #include "dlista_function.h" int main(void) { int elección = 0, pos; char *dato; dato = malloc(50); dl_Lista *lista; dl_Elemento *piloto = NULL; lista = (dl_Lista *) malloc(sizeof(dl_Lista)); inicialización(lista); while (elección != 7) { elección = menu(lista); switch (elección) { case 1: printf("Ingrese un elemento: "); scanf("%s", dato); getchar(); if (lista->tamaño == 0) inserción_en_lista_vacia(lista, dato); else ins_inicio_lista(lista, dato); printf("%d elementos: deb=%s, fin=%s ", lista->tamaño, lista->inicio->dato, lista->fin->dato); muestra(lista); break; case 2: printf("Ingrese un elemento: "); scanf("%s", dato); getchar(); ins_fin_lista(lista, dato); printf("%d elementos: deb=%s, fin=%s ", lista->tamaño, lista->inicio->dato, lista->fin->dato); muestra(lista); break; case 3: if (lista->tamaño == 1) { printf("Utilizar la inserción al inicio o al final (Ingrese Menu: 1 ó 2)\n"); break; } printf("Ingrese un elemento: "); scanf("%s", dato); getchar(); do { printf("Ingrese la posición: "); scanf("%d", &pos); } while (pos < 1 || pos > lista->tamaño); getchar(); ins_antes(lista, dato, pos); printf("%d elementos: deb=%s, fin=%s ", lista->tamaño, lista->inicio->dato, lista->fin->dato); muestra(lista); break; case 4: if (lista->tamaño == 1) { printf("Utilizar la inserción al inicio o al final (Ingrese Menu: 1 ó 2)\n"); break; } printf("Ingrese un elemento: "); scanf("%s", dato); getchar(); do { printf("Ingrese la posición: "); scanf("%d", &pos); } while (pos < 1 || pos > lista->tamaño); getchar(); ins_después(lista, dato, pos); printf("%d elementos: deb=%s, fin=%s ", lista->tamaño, lista->inicio->dato, lista->fin->dato); muestra(lista); break; case 5: do { printf("Ingrese la posición: "); scanf("%d", &pos); } while (pos < 1 || pos > lista->tamaño); getchar(); supp(lista, pos); if (lista->tamaño != 0) printf("%d elementos: deb=%s, fin=%s ", lista->tamaño, lista->inicio->dato, lista->fin->dato); else printf("Lista vacía: %d elementos", lista->tamaño); muestra(lista); break; case 6: destruir(lista); printf("La lista ha sido destruida: %d elementos\n", lista->tamaño); break; } } return 0; }