Listas doblemente enlazadas

Diciembre 2016


Listas doblemente enlazadas


Requisitos

Los requisitos previos son el conocimiento de tipos de datos, estructuras, el uso de typedef, los punteros, las funciones usuario y las listas enlazadas simples.

Introducción

El objetivo de este artículo es la comprensión de las listas doblemente enlazadas.


Las listas doblemente enlazadas pueden ser utilizadas cuando son necesarias varias operaciones de inserción o eliminación de elementos.

Definición

Las listas doblemente enlazadas son estructuras de datos semejantes a las listas enlazadas simples.
La asignación de memoria es hecha al momento de la ejecución.

En cambio, en relación a la listas enlazada simple 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.

Operaciones sobre la lista doblemente enlazadas

Para la inserción y la eliminación, una sola función bastará si está bien concebida en función de las necesidades. Sin embargo, debo recordar que este artículo es puramente didáctico. Por esta razón he 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 hecha 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.


====Cómo 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, si no 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 cierta posición 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 ultimo 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 encontrase en cualquier posición en la lista.

En relación a la lista enlazada simple en el que la eliminación solo 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 ultima posición (el ultimo 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 numero de elementos de la lista, el puntero sup_elemento contendrá la dirección del ultimo elemento, hacemos apuntar al puntero siguiente del penúltimo elemento (es el elemento hacia el que apunta el puntero anterior del ultimo 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 ultimo elemento o del ultimo al 1er elemento.
La condición para detener es dada por el puntero siguiente del ultimo 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);
}

Ejemplo completo

dlista.h

/* ---------- dlista.h ----------- */
typedef struct dl_ElementooLista{
char *dato;
struct dl_ElementoLista *anterior;
struct dl_ElementoLista *siguiente;
} dl_Elemento;

typedef struct dl_ListaIdentificar{
dl_Elemento *inicio;
dl_Elemento *fin;
int tamaño;
} dl_Lista;

/* inicialización de la liste */
void inicialización (dl_Lista * lista);
dl_Elemento *alloc (dl_Elemento * nuevo_elemento);

/* INSERCION */
int ins_en_lista_vacia (dl_Lista * lista, char *dato);
int ins_inicio_lista(dl_Lista * lista, char *dato);
int ins_fin_lista(dl_Lista * lista, char *dato);
int ins_después (dl_Lista * lista, char *dato, int pos);
int ins_antes (dl_Lista * lista, char *dato, int pos);


/*ELIMINACION*/
int sup(dl_Lista *liste, int pos);
void muestra (dl_Lista * lista);

/**************************/
void muestra_inv (dl_Lista * lista);
void destruir (dl_Lista * 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; <gras>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; <gras>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 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){ /* 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;<gras>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 choix; 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

/**********************\

  • 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(liste,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 posicion: "); 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("liste vide : %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;}/* -------- FIN dlista.c --------- */

Consulta también :
El documento «Listas doblemente enlazadas» de CCM (es.ccm.net) se encuentra disponible bajo una licencia Creative Commons. Puedes copiarlo o modificarlo siempre y cuando respetes las condiciones de dicha licencia y des crédito a CCM.