Está en la página 1de 28

Estructura de Datos

Listas Doblemente Enlazadas

Sesion 4
Introducción
• El TDA lista doblemente enlazada, al igual que la lista enlazada, es
un TDA dinámico lineal pero, a diferencia de este, cada nodo de la
lista doblemente enlazada contiene dos punteros, de forma que
uno apunta al siguiente nodo y el otro al predecesor. Esta
característica, permite que se pueda recorrer la lista en ambos
sentidos, cosa que no es posible en las listas simples.
• 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 ultimo


elemento y/o del ultimo al primer elemento
La construcción del modelo de un elemento de la lista
doblemente enlazadas
Definicion de la estructura del NODO
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, en caso
contrario no podrán 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 _nodo


{
int nro;
struct _nodo *sgte;
struct _nodo *ant;
}tipoNodo;

typedef tipoNodo *pNodo;


typedef tipoNodo *Lista;
La construcción del modelo de un elemento de la lista doblemente
enlazadas
Para tener el control de la lista es preferible conservar algunos elementos: el
primer elemento, el último elemento, el número de elementos.
Para ello, será utilizada otra estructura (no es obligatorio, pueden ser utilizadas
variables).
typedef struct identificacion
{
int nrnodos;
struct tipoNodo *inicio;
struct tipoNodo *fin;
}idLista;

typedef idLista idenLista;

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 numero de elementos de la lista cualquiera que sea la operación efectuada
sobre la lista.
Operaciones sobre Listas Doblemente Enlazadas

1. Insertar nodos
1. Inicio de la lista
2. Final de lal lista
3. En posición Intermedia
2. Mostrar nodos
1. Mostrar ida
2. Mostrar de vuelta
3. Elimininar nodos
1. Eliminar primer nodo
2. Eliminar ultimo nodo
3. Eliminar nodo de una posición especifica
Inserción de un Nuevo Nodo
Para añadir un elemento a la lista hay varias
situaciones:
1 a. Inserción en una lista vacía
1.b. Inserción al inicio de la lista
1.c. Inserción al final de la lista
1.d. Inserción en una posición especifica.
Operaciones sobre Listas Doblemente Enlazadas
Inserción de un elemento en la lista

Pasos a considerar en el algoritmo de inserción y registro de los elementos:


• Declaración del elemento a insertar
• Asignación de la memoria para el nuevo elemento
• Rellenar el contenido del campo de datos
• Actualizar los punteros hacia el elemento anterior y el elemento siguiente
• Actualizar los punteros hacia el 1er y ultimo elemento si es necesario.
– Caso particular: en una lista con un solo elemento, el primero es al
mismo tiempo el último.
– Actualizar el tamaño de la lista
Operaciones sobre Listas Doblemente Enlazadas

void InsertaVacia(Lista &lista,int


valor)
{
tipoNodo *nuevo;
nuevo = new tipoNodo; NULL ant nro sgte NULL
nuevo->nro=valor;
nuevo->sgte=NULL;
nuevo->ant=NULL; valor
lista=nuevo;
}
Operaciones sobre la lista doblemente enlazadas
Si se utiliza el registro de primer y ultimo nodo

Funcion de Inicializacion:

void inicialización (idLista &idenLista);

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.

La función

void inicialización (idLista &idenLista)


{
idenLista->inicio = NULL;
idenLista->fin = NULL;
idenLista->nrnodos= 0;
}
1.a. Inserción al inicio
void insertarinicio(Tnodo &lista,int valor){ NULL nro NULL

tiponodo *nuevo,*q;
nuevo
nuevo=new (tiponodo); valor
nuevo->nro=valor;
nuevo->ant=NULL;
nuevo->sgte=NULL;
if(lista==NULL) NULL NULL
lista = nuevo;
else{ lista

lista->ant=nuevo;
nuevo->sgte=lista;
lista=nuevo; lista
NULL ant valor sgte
}
}
1.b. Inserción al final
NULL nro NULL

void insertarfinal(Tnodo &lista,int valor)


{ nuevo
Tnodo t,q; valor
q=new(tiponodo);
q->nro=valor;
q->ant=NULL;
NULL NULL
q->sgte=NULL;

if(lista==NULL){ lista t
lista=q;
}

q->sgte ant valor sgte NULL


1.b. Inserción al final
if(lista==NULL){
lista=q;
}else{
t=lista;
while(t->sgte !=NULL){
t=t->sgte;
}
t->sgte=q; q
q->ant=t;
} NULL NULL

} lista t
t->sgte = q q->ante = t
1.c. Insertar en una posicion
NULL nro NULL

void insertarfinal(Tnodo &lista,int valor)


{ nuevo
Tnodo t,q; valor
q=new(tiponodo);
q->nro=valor;
q->ant=NULL;
NULL NULL
q->sgte=NULL;
lista t
if(lista==NULL){
lista=q;
}

q->sgte ant valor sgte NULL


4. 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 devuelve -1 en caso de error, si no devuelve 0.

La inserción se efectuara 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.

Etapas:asignación de memoria al nuevo elemento


• rellenar el campo de datos del nuevo elemento
• Elegir 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 hacia 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
• el tamaño se incrementa en una unidad
1.d. Insertar en una posición específica
void insertar_entre_nodos(Tlista &lista,int pos,int valor){
int c=0,i=1;
Tnodo *t,*q;

t=lista; NULL NULL


//********* Recorre lista para saber nr nodos***
ant valor sgte
while (t!=NULL){
t=t->sgte;
c++; q
}
//*****************************************
if(pos>c || pos ==1){
cout<<“Error: No es posición valida"<<endl;}
else{
t=lista;
while (i!=pos){ t
t=t->sgte; (4)
NULL s a NULL
i++;
} (3)
lista
q = new(struct nodo);
q->dato=valor; (2) (1) q->ant=t->ant
q->ant=t->ant; (1) (2) q->sgte=t
q->sgte=t; a s (3) t->ant->sgte=q
t->ant->sgte=q; (4) t->ant=q
t->ant=q; q
}

}
2.a. Mostrar lista en sentido de ida
void mostrarida(Tnodo lista){
Tnodo actual;
actual = lista;

while(actual!=NULL){
cout<<actual->nro<<"-->";
actual=actual->sgte;
}
cout<<"NULL";

NULL NULL

} lista actual
2.b. Mostrar lista en sentido de vuelta
void mostrarvuelta(Tnodo lista){

Tnodo actual;
actual = lista;

while(actual!=NULL)
actual=actual->sgte;

cout<<"Null <-- ";

while(actual->ant!=NULL){
cout<<actual->nro<<"<--";
actual=actual->ant;
}

}
NULL NULL

lista actual
3. Eliminación de un elemento de la lista
A continuación el algoritmo para eliminar un elemento de la lista: uso de un puntero
temporal para guardar 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. Liberar la memoria ocupada por el elemento eliminado y
actualizar el tamaño de la lista

Para eliminar un elemento de la lista hay varias situaciones:


1. Eliminación al inicio de la lista
2. Eliminación al final de la lista
3. Eliminación en una posición
Eliminar el único nodo en una lista doblemente enlazada
En este caso, ese nodo será el apuntado por Lista.

1. Eliminamos el nodo.

2. Hacemos que Lista apunte a NULL.


Eliminar primer nodo
NULL NULL

lista

t = lista
t->sgte->ant = NULL;

lista = t->sgte;
delete(t); NULL
NULL

t lista
Eliminar el ultimo nodo

NULL NULL

lista t

NULL NULL

lista
t

t = lista
while(t->sgte!=NULL){
t = t->sgte;
}
t->ant->sgte = NULL;
delete(t);
Eliminar un nodo de una posicion intermedia
NULL
NULL

lista t

NULL
NULL

lista
t = lista
t while( i != pos || t->sgte != NULL){
t = t->sgte;
}
t->ant->sgte = t->sgte;
t->sgte->ant = t->ant;

delete(t);
3.d. 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.
La función
/* destruir la lista */
void destruir (Lista &lista){
Tlista t;
while (lista->sgte != NULL) {
t=lista
lista= lista->sgte;
delete(t);
}
delete(t);
lista=NULL;

También podría gustarte