Listas dinámicas simplemente enlazadas

Anuncio
Introducción: una simple colección
™ Implemente una clase denominada Lista. La clase deberá
mantener una colección de números y proveer los
siguientes
i i t métodos:
ét d
public class Lista{
public void agregarAlFinal(int data){
...
}
public void imprimirContenido(){
...
}
public boolean estaContenido(int data){
...
}
public boolean eliminar(int data){
...
}
}
Listas dinámicas simplemente enlazadas
Franco Guidi Polanco
Escuela de Ingeniería Industrial
Pontificia Universidad Católica de Valparaíso, Chile
f d@
[email protected]
l
Actualización: 17 de noviembre de 2010
Franco Guidi Polanco (PUCV-EII)
Introducción: una simple colección
17-11-2010
2
Aproximación al uso de listas dinámicas
™ Supongamos la
clase Pontífice.
™Recuerda la clase que has implementado… más
adelante la revisitaremos.
public class Pontífice{
private String Nombre;
private Pontifice sucesor;
public Pontífice(String n Pontífice s){
nombre = n;
sucesor = s;
}
public void setNombre(String n){
nombre = n;
}
public String
p
g g
getNombre(){
(){
return nombre;
}
public void setSucesor(Pontífice s){
sucesor = s;
;
}
public Pontífice getSucesor(){
return sucesor;
}
™ Los objetos de
esta clase
tienen un
nombre y una
referencia a un
sucesor. El
sucesor es un
objeto
bj t de
d la
l
misma clase:
}
Franco Guidi Polanco (PUCV-EII)
17-11-2010
3
Franco Guidi Polanco (PUCV-EII)
17-11-2010
4
Aproximación al uso de listas dinámicas
Aproximación al uso de listas dinámicas
™ Suponga que una aplicación tiene una variable de tipo
Pontífice.
™ Dado:
“Pedro”
Pontífice p2 = new Pontífice (“Lino” , null)
Pontífice p1 = new Pontífice(“Pedro”, p2);
™ Explique qué hace el siguiente código:
™ Podemos imaginar que en la memoria existirán dos objetos
relacionados de la siguiente forma:
1A04
1A04
30F1
“Pedro” 30F1
“Lino”
“Lino”
p1
System.out.println( p1.getNombre() );
™ Y el siguiente:
null
System.out.println( p1.getSucesor().getNombre() );
p1
™ Representaremos la situación anterior sin hacer explícitas
las direcciones de memoria (excepto null):
“Pedro”
™ Y el siguiente:
Pontifice aux = p1.getSucesor();
System.out.println( aux.getNombre() );
“Lino”
p1
Franco Guidi Polanco (PUCV-EII)
17-11-2010
5
Franco Guidi Polanco (PUCV-EII)
Aproximación al uso de listas dinámicas: recorrido
™Dado:
“Pedro”
6
Aproximación al uso de listas dinámicas: recorrido
™ Dado:
“Lino”
“Anacleto”
...
“Pedro”
“Benedicto
XVI”
“Anacleto”
...
“Benedicto
XVI”
™ La búsqueda de un nombres se logra mediante el siguiente
código:
™La impresión de todos los nombres se logra
mediante el siguiente código:
String buscado = ... // aquí se asigna un valor
boolean está = false;
Pontífice aux = p1;
p
while( aux != null ){
if( aux.getNombre().equals( buscado ) )
está = true;
aux = aux.getSucesor();
aux getSucesor();
}
if( está )
System.out.println( buscado + “ sí está” );
else
System.out.println( buscado + “ no está” );
Pontífice aux = p1;
while( aux != null ){
System out println( aux
System.out.println(
aux.getNombre()
getNombre() );
aux = aux.getSucesor();
}
17-11-2010
“Lino”
p1
p1
Franco Guidi Polanco (PUCV-EII)
17-11-2010
7
Franco Guidi Polanco (PUCV-EII)
17-11-2010
8
Esquema tentativo de una lista dinámica
simplemente enlazada
Listas dinámicas simplemente enlazadas
™Son estructuras dinámicas: se asigna memoria
para los elementos de la lista en la medida que es
necesario.
™Cada elemento se almacena en una variable
dinámica denominada nodo.
™En la lista simplemente enlazada, cada nodo
apunta all nodo
d que contiene ell elemento
l
siguiente
Nodos
data
data
data
data
h d
head
null
ListaEnlazada
Franco Guidi Polanco (PUCV-EII)
17-11-2010
9
™Los nodos de una lista contendrán datos del tipo
declarado en la estructura del nodo. Por ejemplo:
10
™ Implementar la colección discutida al inicio, pero mediante
una lista dinámica simplemente enlazada.
ƒ Tipos primitivos (byte, int, boolean, char, etc.)
ƒ Referencias a objetos
™En los siguientes ejemplos consideraremos el uso
de listas de enteros, aunque las técnicas que serán
d
descritas
it son aplicables
li bl a cualquier
l i otro
t “tipo”
“ti ” de
d
lista.
17-11-2010
17-11-2010
Implementación de una lista dinámica
simplemente enlazada
Datos contenidos en la lista
Franco Guidi Polanco (PUCV-EII)
Franco Guidi Polanco (PUCV-EII)
11
public class Lista{
public void agregarAlFinal(int data){
...
}
public void imprimirContenido(){
...
}
public boolean estaContenido(int data){
...
}
public boolean eliminar(int data){
...
}
}
Franco Guidi Polanco (PUCV-EII)
17-11-2010
12
Diagrama de clases de una lista dinámica
simplemente enlazada
Una lista dinámica simplemente enlazada (versión
preliminar)
™Diagrama de clases (lista de enteros):
™ Declaración de la Lista:
public class Lista{
private Nodo head = null;
public void agregarAlFinal(int data){
...
}
public void imprimirContenido(){
...
}
public boolean estaContenido(int data){
...
}
public boolean eliminar(int data){
...
}
}
0..1
next
Lista
Nodo
head
agregarAlFinal(d:Data)
estáContenido(d:Data):boolean
eliminar(d:Data):boolean
imprimirContenido()
Franco Guidi Polanco (PUCV-EII)
0..1 data:int
getData():int
setNext(n:Nodo)
getNext():Nodo
Nodo(d:Data,n:Nodo)
(
,
)
17-11-2010
13
Nodos en una lista dinámica simplemente
enlazada
Franco Guidi Polanco (PUCV-EII)
17-11-2010
Inserción en la lista
™Insertar elementos:
public class Nodo{
private int data;
private Nodo next;
public Nodo(int d, Nodo n){
data = d;
next = n;
;
}
public int getData(){
return data;
}
public Nodo getNext(){
return next;
}
public void setNext(Nodo n){
next = n;
}
17-11-2010
Ejemplo: [ 25, 1, 14, 4 ]
ƒ Al final de la lista
25
1
14
4
head
null
ƒ Manteniendo un orden
1
4
14
25
head
null
ƒ Al inicio
i i i de
d la
l lista
li t
4
14
h d
head
15
Franco Guidi Polanco (PUCV-EII)
1
25
null
}
Franco Guidi Polanco (PUCV-EII)
14
17-11-2010
16
Inserción de elementos al final de la lista
Inserción de elementos al final de la lista
™Caso 1: la lista está vacía (variable head contiene
null)
™Caso 2 (general): la lista tiene al menos un
elemento
25
h d
head
h d
head
null
25
17-11-2010
null
aux
public Lista{
...
public void agregarAlFinal(int dato){
...
head = new Nodo( dato
dato, null );
...
}
...
}
Franco Guidi Polanco (PUCV-EII)
1
head
null
1. ubicar último nodo de la lista
(aquél cuya variable next
contiene null))
2. Instanciar el nuevo nodo
con el contenido indicado
3. Asignar el nuevo nodo a la
variable next del último
nodo (asegurándose de que
la variable next del nuevo
nodo sea igual a null)
25
14
1
head
null
aux
17
Franco Guidi Polanco (PUCV-EII)
Inserción de elementos al final de la lista
aux.setNext(new Nodo(dato, null));
17-11-2010
18
Recorrido de la lista
™Caso general:
™Método que imprime el contenido de la lista:
public class Lista{
...
public void agregarAlFinal(int dato){
Nodo
odo nuevo
ue o = new
e Nodo(dato,
odo(dato, null);
u );
if( head == null )
head = nuevo;
else{
Nodo aux = head;
while( aux.getNext() != null)
aux = aux.getNext();
aux.setNext( nuevo );
}
public class Lista{
...
public void imprimirContenido(){
p
p
(){
Nodo aux = head;
while( aux != null ){
System.out.print( aux.getData() + "; " );
aux = aux.getNext();
}
System.out.println();
...
}
}
...
}
Franco Guidi Polanco (PUCV-EII)
17-11-2010
19
Franco Guidi Polanco (PUCV-EII)
17-11-2010
20
Búsqueda en la lista
Eliminación de un elemento
™Retorna true si el elemento está contenido en la
lista
™Requiere identificar el nodo a borrar.
™Caso 1: es el primer nodo de la lista
public class Lista{
...
public boolean estaContenido(int data){
Nodo aux = head;
while( aux != null ){
if( data == aux.getData() )
return true;
aux = aux.getNext();
}
return false;
25
1
14
4
head
null
head = head.getNext();
g
();
25
1
14
4
head
Sin otras
Si
t
referencias:
f
i candidato
did t a eliminación
li i ió
(recolector de basura de Java)
}
null
ll
...
1
}
14
head
Franco Guidi Polanco (PUCV-EII)
17-11-2010
21
Eliminación de un elemento
1
14
4
head
null
aux.setNext(aux.getNext().getNext());
aux
25
1
14
4
head
Sin otras referencias: candidato a eliminación
(recolector de basura de Java)
25
1
head
Franco Guidi Polanco (PUCV-EII)
null
4
null
17-11-2010
null
17-11-2010
22
Eliminación de un elemento
™ Caso 2 (general): no es el primer nodo de la lista
25
Franco Guidi Polanco (PUCV-EII)
4
23
public class Lista{
...
public boolean eliminar(int data){
if( head != null)
if( head.getData() == data ){
head = head.getNext();
return true;
}else{
Nodo aux = head;
while( aux.getNext() != null ){
if( aux.getNext().getData() == data ){
aux.setNext(
( aux.getNext().getNext()
()
() )
);
return true;
}
g
();
aux = aux.getNext();
}
}
return false;
}
...
}
Franco Guidi Polanco (PUCV-EII)
17-11-2010
24
Simplificación de la implementación propuesta:
uso de un nodo “fantasma”
Lista dinámica simplemente enlazada con nodo
fantasma
™En la implementación descrita se deben hacer
excepciones al insertar y eliminar el nodo del
comienzo de la lista.
™Lista vacía:
public class Lista{
Nodo head;
public Lista(){
head = new Nodo(0, null);
}
head
™El manejo
j se simplifica
i lifi sii se utiliza
tili un nodo
d
“fantasma”:
...
null
™Lista con elementos:
ƒ Es un nodo siempre presente en la primera posición de
la lista
ƒ Su contenido es irrelevante (el valor u
objeto contenido no forma parte de la lista).
}
V l irrelevante
Valor
i l
t
25
1
4
head
null
Primer elemento de la lista
Franco Guidi Polanco (PUCV-EII)
17-11-2010
25
Operación de inserción en la lista con nodo
fantasma
Franco Guidi Polanco (PUCV-EII)
17-11-2010
26
Eliminación del primer elemento en la lista con
nodo fantasma
™La inserción del primer elemento de la lista entra
en el caso general:
™La eliminación del primer elemento de la lista entra
en el caso general:
1
head
null
aux
Clase
Lista
aux
aux.setNext(aux.getNext().getNext());
aux.setNext(new Nodo(dato, null));
14
public void agregarAlFinal(int dato){
Nodo aux = head;
while(
hil ( aux.getNext()
tN t() !
!= null)
ll)
aux = aux.getNext();
aux.setNext( new Nodo(dato, null) );
}
1
4
head
null
Sin otras referencias: candidato a eliminación
(recolector de basura de Java)
}
Franco Guidi Polanco (PUCV-EII)
17-11-2010
27
Franco Guidi Polanco (PUCV-EII)
17-11-2010
28
Eliminación del primer elemento en la lista con
nodo fantasma (cont.)
Mejora al procedimiento de inserción de
elementos al final de la lista
™ El procedimiento descrito anteriormente requiere que todas
las veces sea encontrado el último elemento de la lista.
™ Más conveniente: tener una variable de instancia que
siempre
p referencie al último elemento de la lista.
public boolean eliminar(int data){
Nodo aux = head;
while(
hil ( aux.getNext()
t
t() !=
! null
ll ){
if( aux.getNext().getData() == data ){
aux.setNext( aux.getNext().getNext() );
;
return true;
}
aux = aux.getNext();
}
™ Esto aplica a listas con o sin nodo fantasma (con pequeños
cambios).
cambios)
return false;
}
Franco Guidi Polanco (PUCV-EII)
17-11-2010
29
Mejora al procedimiento de inserción de
elementos al final de la lista (cont.)
17-11-2010
30
Mejora al procedimiento de inserción de elementos al final
de la lista (cont.)
™ La variable de instancia tail mantiene siempre la
referencia al último elemento:
™Diagrama de clases:
Lista
1..1
agregarAlFinal(d:Data)
estáContenido(d:Data)
á
eliminar(d:Data):boolean
imprimirContenido()
Franco Guidi Polanco (PUCV-EII)
head
1..1
1..1
tail
Nodo
data: int
getData():Data
tD t () D t
setNext(n:Nodo)
getNext():Nodo
Nodo(d:Data,n:Nodo)
head
null
public class Lista{
Nodo head, tail;
public Lista(){
head = new Nodo(0, null);
tail = head;
}
tail
...
}
™Diagrama de objetos:
Lista
head
25
ghost:Nodo
1stNode:Nodo
2ndNode:Nodo
data = 20
data = -1
17-11-2010
1
4
null
tail
tail
Franco Guidi Polanco (PUCV-EII)
head
31
Franco Guidi Polanco (PUCV-EII)
17-11-2010
32
Mejora al procedimiento de inserción de elementos al final
de la lista (cont.)
™ El método agregarAlFinal ya no requiere recorrer la
lista para ubicar el último nodo:
public void agregarAlFinal(int dato){
Nodo aux = new Nodo(dato, null) ;
tail setNext( aux );
tail.setNext(
tail = aux;
™ Ejercicio 1: implemente el método:
agregarEnOrden(int dato)
Versión con
nodo fantasma
que recibe un entero y lo agrega como
primer elemento.
™ La varaible tail es actualizada después de la inserción.
™ Notar que el procedimiento de eliminación debe actualizar
la referencia tail si se remueve el último nodo de la lista.
17-11-2010
que recibe un entero y lo agrega en orden
ascendente a la lista.
™ Ejercicio 2: implemente el método
agregarAlInicio(int dato)
}
Franco Guidi Polanco (PUCV-EII)
Inserción en orden/al inicio
33
Resumen listas dinámicas simplemente enlazadas
™Útiles para guardar un número no predefinido de
elementos.
™Distintas disciplinas para mantener los datos
ordenados (y para removerlos).
™El acceso a los nodos es secuencial; el recorrido es
en una sola dirección (Ejercicio: confrontar con
arreglos)
l )
Franco Guidi Polanco (PUCV-EII)
17-11-2010
34
Otras estructuras dinámicas: listas doblemente
enlazadas
™ Están diseñadas para un acceso fácil al nodo siguiente y al
anterior.
™ Cada nodo contiene dos referencias: una apuntando al nodo
siguiente, y otra apuntando al nodo anterior.
™ El acceso a los nodos sigue siendo secuencial.
secuencial
™ La técnica del nodo fantasma puede ser útil también en este
tipo
p de lista.
1
14
4
head
null
null
ll
Franco Guidi Polanco (PUCV-EII)
17-11-2010
35
Franco Guidi Polanco (PUCV-EII)
17-11-2010
36
Otras estructuras dinámicas: lista circular
™Cada nodo tiene un sucesor. Conceptualmente no
hay “primer” ni “último” nodo.
™Sus elementos pueden ser visitados
secuencialmente a partir de cualquier nodo.
25
1
14
4
h d
head
Franco Guidi Polanco (PUCV-EII)
17-11-2010
37
Descargar