Listas enlazadas - Prof. Antonio J. Moreno Checa

Anuncio
Listas enlazadas
A.J.M.Checa<[email protected]>
February 5, 2008
IMPORTANTE:
La Práctica planteada en la última sección de estos apuntes supone un 50% de la nota final.
Será entregada y explicada en una de las dos convocatorias de febrero de 2008.
1
Introducción
Las listas enlazadas son elementos del mismo tipo enlazados mediante una dirección a la que
llamaremos nodo. En nuestro caso, los elementos serán estructuras y los nodos punteros al
mismo tipo de estructura. En la figura 1 se representa el primer elemento de una lista, al que
Figure 1: Primer elemento
hemos denominado ini1. c1, c2,...,son los campos del elemento que contendrán información y
nodo es un campo especial, ya que ha de contener la dirección del siguiente elemento, al que
hemos denominado act. En la figura 2 se representa una lista enlazada. El acceso a cualquiera
de sus elementos es secuencial, ya que para llegar hasta él hemos de recorrer los que le preceden.
1
Es importante recordar que estos nombre se refieren a direcciones asignadas mediante la función malloc a las
estructuras que formarán la lista enlazadas.
1
Figure 2: Lista enlazada
2
Generación de una lista simplemente enlazada
Una lista es simplemente enlazada cuando cada elemento posee un único nodo que enlaza con
el siguiente elemento.
En primer lugar, antes de enlazar el primero con el segundo, hemos de tener ambos: como
Figure 3: Los dos primeros elementos sin enlazar
se muestra en la figura 3. A continuación enlazamos el primero con el segundo; aunque esto
mismo lo hubiéramos podido hacer sin utilizar act:
2
ini -> sig = (struct *lista) malloc(sizeof(struct lista));
Sin embargo nosotros seguiremos utilizando el puntero act, pues como veremos a continuación, resulta muy útil para generar una lista.
2
Figure 4: Los dos primeros elementos enlazados
Enlazaremos el segundo con un tercero, previa generación de un nuevo elemento que llamaremos new;
4
5
new = (struct *lista) malloc(sizeof(struct lista));
act -> sig = new;
pero hacer esto es equivalente a;
4
act -> sig =
(struct *lista) malloc(sizeof(struct lista));
con lo cual no es necesario introducir un nuevo puntero a estructura new. Ya estamos en
condiciones de generar automáticamente una lista enlazada de N elementos. No olvidemos que
la lista es de acceso secuencial, lo cual quiere decir que solo es necesario conocer la dirección
del primer elemento de la lista;
for(i=0 , i<N-1, i++)
{
act -> sig = (struct *lista) malloc(sizeof(struct lista));
act = act -> sig;
}
La sentencia
act = act -> sig;
es para actualizar el elemento actual. No se pierde ninguna información, ya que los nodos se
van guardando en elementos anteriores. Por otra parte, este bucle se realiza N − 1 veces, pues
ya tenemos el primer elemento ini.
3
El código completo lo resumimos en el siguiente cuadro mediante la declaración de una determinada estructura con un único campo;
#include <stdlib.h>
struct lista{
int n;
struct lista *sig;
} *ini,*act;
main(){
int i;
ini = (struct *lista) malloc(sizeof(struct lista));
act=ini;
for(i=0 , i<N-1, i++)
{
act -> sig = (struct *lista) malloc(sizeof(struct lista));
act = act -> sig;
}
act -> sig = NULL;
return 0;
}
El último comando
act -> sig = NULL;
es útil para cerrar la lista, o lo que es lo mismo, para saber cual es el último elemento.
2.1
Ejercicio
a. Implemente una función que permita eliminar o insertar un determinado elemento en
una lista simplemente enlazada, siempre que no sea el primero o el último.
b. Como en el caso anterior, pero teniendo en cuenta si el elemento es el primero o el
último.
4
3
Generación listas doblemente enlazada
Decimos que una lista está doblemente enlazada cuando cada elemento posee dos nodos, uno
que contiene la dirección del siguiente elemento y otro que contiene la dirección del elemento
anterior.
struct lista{
int n;
struct lista *sig, *ant;
} *ini,*act,*ult;
La estructura anterior puede utilizarse para crear la lista enlazada de la figura 5.En este caso
particular la lista se dice que es circular, pues el último elemento de la lista ult contiene la dirección del primero ini, y a su vez el primero se enlaza con ult, y como es circular, hemos de
Figure 5: Lista circular doblemente enlazada
guardar dos direcciones, ini y ult.
El siguiente programa puede utilizarse para implementar una lista no circular doblemente enlazada.
#include <stdlib.h>
struct lista{
int n;
struct lista *sig, *ant;
} *ini,*act,*new;
int main(){
int i;
ini = (struct *lista) malloc(sizeof(struct lista));
5
ini -> ant
= NULL;
act=ini;
for(i=0 ;
{
act ->
(act ->
act =
}
i<N-1; i++)
sig
= (struct *lista) malloc(sizeof(struct lista));
sig) -> ant = act;
act -> sig ;
act -> sig = NULL;
return 0;
}
4
Añadir y eliminar elementos de una lista
Estas notas solo son indicativas respecto a la inserción o extracción de elementos de una lista
doblemente enlazada. No tiene en cuenta como hacerlo si se trata del primer o último elemento. Esta tarea ha de ser desarrollada por el alumno como parte de la práctica que se detalla
en la introducción.
la siguiente función permite añadir un elemento en una lista ordenada por el campo n,
/* Esta función inserta un nuevo elemento (new =malloc(sizeof(struct lista)); )
entre los elementos menor y mayor que Nel.
Nel se compara con el contenido del campo n del elemento actual y con el
contenido del campo n del elemento siguiente mediante la instrucción
if( (Nel > act->n )&&(Nel < (act->sig)->n )).*/
#include <stdlib.h>
struct lista{
int n;
struct lista *sig, *ant;
} *ini,*act,*new;
6
void aniadirElemento(struct lista *act,int Nel){
while(act!=NULL)
{
if( (Nel > act->n )&&(Nel < (act->sig)->n )){
new =malloc(sizeof(struct lista));
new->n=Nel;
new->sig=act->sig;
new->ant=act;
(act->sig)->ant=new;
act->sig=new;
return;
}
act=act->sig;
}
return;
}
}
}
La sentencia while(act! = N U LL) es válida para una lista que no se circular, pues el último
elemento de la lista es el único con dirección nula.
la siguiente función permite añadir un elemento en una lista ordenada por el campo n,
/* Esta función elimina el elemento cuyo campo n sea Nel*/
7
void borrarElemento(struct lista *act,int Nel){
while(act!=NULL)
{
if(act->n==Nel){
(act->ant)->sig=act->sig;
(act->sig)->ant=act->ant;
free(act);
return;
}
act=act->sig;
}
return;
}
}
}
5
Práctica
Escriba un programa en C para crear un lista circular doblemente enlazada con dos opciones2
a. Eliminar un determinado elemento de la lista.
b. Añadir un nuevo elemento.
2
Tenga cuidado si se trata del primer o último elemento.
8
Descargar