Está en la página 1de 12

Captulo 3

Listas
3.1 Introducci on
Las listas las tenemos en muchos casos en la vida real: lista de compras, lista
de utiles escolares, lista de invitados, lista de pendientes, lista de tareas, lista
de discos, etc. Pero, que es una lista? Una lista es una estructura de datos
con la propiedad que se pueden agregar y suprimir datos en cualquier lugar.
El tipo de datos Lista debe tener las siguientes propiedades:
Determinar si esta vaca la lista.
Limpiar la lista.
Agregar un elemento.
Encontrar un elemento. (por valor).
Actualizar un elemento.
Eliminar un elemento.
Como caractersticas de las listas se tiene que de antemano se desconoce
cuantos elementos tendra esta. Es irrelevante el orden de los elementos y el
manejo de ellos, es decir las inserciones y supresiones pueden ser de cualquier
dato no por posicion.
La interfaz para la clase de las listas es:
1
3.2. IMPLEMENTACI

ON 2
interface Listable {
public boolean estaVaca();
public void limpiar();
public Object primerElemento();
public void agregar(Object x); //Inserta al inicio de la lista
public boolean contiene(Object x);
public void eliminar(Object x); //Borra el primer nodo que tenga valor x
public void sustituir(Object orig, Object nuevo);
public java.util.Iterator elementos();
}
Propiedades que se esperan de una lista:
estaVaca. Devuelve true si la lista esta vaca y false en otro caso.
limpiar. Elimina todos los elementos de la lista, es decir el tama no de
la lista despues de esta operacion es cero..
primerElemento. Devuelve el valor almacenado en el primer elemento
de la lista. El estado de la lista no se ve alterado.
agregar. Agrega al inicio de la lista el objeto especicado como el
parametro. El tama no de la lista crece en una unidad.
contiene. Regresa true si el elemento esta en la lista y false en otro
caso. Este metodo no cambia el estado de la lista.
eliminar. Si el elemento existe en la lista lo elimina, en caso contra-
rio dispara la excepcion NoSuchElementException. En caso de que la
operacion sea exitosa se reduce el tama no de la lista en una unidad.
sustituir. Si el elemento a sustituir se encuentra en la lista lo susti-
tuye por el segundo parametro, en caso contrario dispara la excepcion
NoSuchElementException. Esta operacion no altera el tama no de la
lista.
3.2 Implementaci on
Las listas se pueden implementar con arreglos pero para evitar el costo de
recorridos durante la insercion o supresion, se puede usar el concepto de lista
3.2. IMPLEMENTACI

ON 3
ligada (Ver gura) la cual consta de un conjunto de nodos, no necesariamente
almacenados en forma adyacente. Cada nodo contiene el elemento y una liga
o enlace a su sucesor.
l
e1 e2 e3 e4 e5
Figura 3.1:
Implementacion usando dos clases: la de la lista ligada (Lista)y la de
nodos (Nodo). La clase de los nodos tinen un elemento que es el dato a guar-
dar en la lista, y una referencia al siguiente nodo, que es la liga. Puede resultar
curioso que se tenga una referencia a un objeto del tipo que esta deniendo
pero es valido hacer esto.
/*
* Clase para manejar los nodos de la lista
*/
class Nodo {
Object elemento;
Nodo sgte;
/**
* Crea un nodo con elemento igual a valor y apuntando al vaco.
* @param valor el Objeto que es el valor de nodo
*/
Nodo(Object valor) {
elemento = valor;
sgte = null;
}
/**
* Crea un nodo despues del indicado, con elemento igual a valor.
* @param valor el Objeto que es el valor de nodo
* @param n el nodo anterior al recien creado
*/
Nodo(Object valor, Nodo n) {
elemento = valor;
3.2. IMPLEMENTACI

ON 4
sgte = n;
}
/*
* Devuelve el valor de un nodo
* @return Object el valor del nodo
*/
public Object daElemento () { return elemento; }
/**
* Devuelve la referencia del siguiente nodo
* @return NOdo el siguietne nodo
*/
public Nodo daSgte() { return sgte;}
}
A continuacion la implementacion de la interfaz, creando la lista ligada
con un nodo centinela al inicio de la misma.
/**
* Listada ligada usando un nodo centinela
*/
public class Lista implements Listable{
private Nodo inicio;
/** Construye la lista */
public Lista() {
inicio = null;
}
/** Prueba que la lista este vaca.
* @return true si esta vaca y false en otro caso.
*/
public boolean estaVaca() {
return inicio == null;
}
/** Crea una lista vaca. */
public void limpiarLista() {
inicio = null;
}
3.2. IMPLEMENTACI

ON 5
/** Devuelve el primer nodo de la lista **/
public Nodo primerElemento() {
return inicio;
}
/**
* Devuelve la posicion del nodo que contiene el dato buscado.
* @param dato el dato a buscar.
* @return un nodo; null si el dato no se encuentra.
*/
public Nodo buscar(Object dato) {
Nodo pos = inicio;
while(pos != null && !pos.elemento.equals(dato))
pos = pos.sgte;
return pos;
}
public void sustituir(Object orig, Object nuevo) {
Nodo n = buscar(orig);
if (n != null)
n.elemento = nuevo;
}
/**
* Inserta el primer elemento de la lista.
* @param dato el dato a agregar.
*/
public void agregar(Object dato) {
inicio = new Nodo(dato,inicio);
/**
* Elimina la primera ocurrencia de un dato.
* @param dato el dato a eliminar.
*/
public void eliminar(Object dato) {
Nodo pos = inicio, anterior = null;
while(pos != null && !pos.elemento.equals(dato)) {
anterior = pos;
pos = pos.sgte;
}
3.3. LISTAS CON DOS CENTINELAS 6
if (pos == null) return; // No lo encontro
if(pos == inicio) // Es el inicio de la lista
inicio = inicio.sgte
else
anterior.sgte = pos.sgte;
}
public java.util.Iterator elementos() {
return new MiIterador();
}
private class MiIterador implements java.util.Iterator {
private Nodo posicion = inicio;
public boolean hasNext() { return posicion != null;}
public Object next() throws java.util.NoSuchElementException {
if (hasNext()) {
Object o = posicion.elemento;
posicion = posicion.sgte;
return o;
}
throw new java.util.NoSuchElementException();
}
public void remove() {
throw new IllegalStateException();
}
}
}
3.3 Listas con dos centinelas
Con la implementacion antes vista se tiene que la operacion de agregar es de
O(1) lo cual es inmejorable. Sin embargo, si se presentara la situacion que
la operacion mas com un es la agregar al nal de la lista, o suprimir el nal
de la lista, esta sera una operacion de orden n porque es necesario recorrer
toda la lista antes de llegar al nal.
3.3. LISTAS CON DOS CENTINELAS 7
public void agregarFinal(Object dato) {
if (estaVaca())
agregar(dato);
else {
while(Nodo p = inicio; p.sgte != null; p = p.sgte)
;
p.sgte = new Nodo(dato);
}
Para que este metodo tambien sea de orden constante es necesario incluir
una nueva referencia que este siempre apuntando al nal de la lista. Es decir,
se puede hacer una implementacion usando dos centinelas: el del inicio y y
otro al nal de la lista. como se presenta aqu:
/**
* Lista ligada usando dos centinelas: uno al inicio y otro al final.
*/
public class ListaF implements Listable {
private Nodo inicio;
private Nodo fin;
private final Comparator prueba;
Con lo cual la implementacion de algunos metodos cambia y se incluyen
nuevos metodos.
/** Construye la lista */
public ListaF() {
inicio = null;
fin = null;
prueba = new DefaultComparator();
}
/** Devuelve el ultimo elemento de la lista **/
public Object ultimoElemento() {
return (estaVaca()) ? null : fin.elemento;
}
/**
* Inserta el primer elemento de la lista.
* @param dato el dato a agregar.
*/
3.4. LISTAS DOBLEMENTE LIGADAS 8
public void agregar(Object dato) {
if (estaVaca())
inicio = fin = new Nodo(dato);
else
inicio = new Nodo(dato,inicio);
}
/**
* Inserta el ultimo elemento de la lista.
* @param dato el dato a agregar.
*/
public void agregar

Ultimo(Object dato) {
if (estaVaca())
inicio = fin = new Nodo(dato);
else
fin = fin.sgte = new Nodo(dato);
}
/**
* Elimina el primer nodo de la lista.
*/
public void eliminarPrimero() {
inicio = inicio.sgte;
}
}
3.4 Listas doblemente ligadas
En ocasiones resulta conveniente poder moverse en ambas direcciones dentro
de la lista. En estos casos es conveniente que cada nodo cuente con un apun-
tador al nodo que le sigue y otro al nodo que le precede. Es decir se requiere
tener una lista con doble liga.
class NodoD {
Object elemento;
NodoD sgte;
NodoD anterior;
/* Constructor de un nodo con valor dado y apuntadores a null.
* @param valor - Objeto que sera el valor del nodo.
3.4. LISTAS DOBLEMENTE LIGADAS 9
*/
NodoD(Object valor) {
elemento = valor;
sgte = null;
anterior = null;
}
/* Constructor de un nodo con valor dado y apuntador siguiente al nodo dado
* El apuntador al nodo anterior es null.
* @param valor - Objeto que sera el valor del nodo.
* @param sig - valor de la referencia siguiente
*/
NodoD(Object valor, NodoD sig) {
elemento = valor;
sgte = sig;
anterior = null;
}
/* Constructor de un nodo con valor dado y apuntador al nodo siguiente y
* al anterior proporcionados.
* @param valor - Objeto que sera el valor del nodo.
* @param ant - valor de la referencia anterior
* @param sig - valor de la referencia siguiente
*/
NodoD(Object valor, NodoD ant, NodoD sig) {
elemento = valor;
anterior = ant;
sgte = sig;
}
}
Con estos nodos la implementacion de la clase para listas ligadas quedara
como sigue:
import java.util.Comparator;
/**
* Lista doblemente ligada con apuntador al inicio y al final de la misma.
* @version Octubre 2006
*/
public class ListaDoble implements Listable{
3.4. LISTAS DOBLEMENTE LIGADAS 10
private NodoD inicio;
private NodoD fin;
private final Comparator prueba;
/** Construye la lista vaca y utiliza el comparador por omision */
public ListaDoble() {
inicio = fin = null;
prueba = new DefaultComparator();
}
/** Construye la lista con el comparador especificado */
public ListaDoble(Comparator c) {
inicio = fin = null;
prueba = c;
}
/** Prueba que la lista este vaca.
* @return true si esta vaca y false en otro caso.
*/
public boolean estaVaca() {
return inicio == null;
}
/** Crea una lista vaca. */
public void limpiar() {
inicio = fin = null;
}
/** Devuelve el primer elemento de la lista
* @return Object - primer elemento de la lista
*/
public Object primerElemento() {
return (estaVaca()) ? null : inicio.elemento;
}
/** Devuelve el ultimo elemento de la lista **/
public Object ultimoElemento() {
return (estaVaca()) ? null : fin.elemento;
}
/** Inserta el primer elemento de la lista
* @param dato - Objeto a agregar al inicio de la lista
*/
public void agregar(Object dato) {
3.4. LISTAS DOBLEMENTE LIGADAS 11
if (estaVaca())
inicio = fin = new NodoD(dato);
else
inicio = inicio.anterior = new NodoD(dato, inicio);
}
/** Inserta el ultimo elemento de la lista
* @param x -- Objeto que se agregara al final de la lista
*/
public void agregar

Ultimo(Object x) {
if (estaVaca())
agregar(x);
else {
NodoD n = new NodoD (x);
fin.sgte = n;
n.anterior = fin;
fin = fin.sgte;
}
}
/**
* Elimina la primera ocurrencia de un dato.
* @param dato el dato a eliminar.
*/
public void eliminar(Object dato) {
NodoD p = inicio;
while(p != null && prueba.compare(p.elemento,dato) != 0)
p = p.sgte;
if (p != null) return; // No encontro el dato a eliminar
if (p == inicio)
eliminarPrimero();
else if (p == fin)
eliminar

Ultimo();
else if(p.sgte != null) {
p.anterior.sgte = p.sgte;
p.sgte.anterior = p.anterior;
}
}
3.4. LISTAS DOBLEMENTE LIGADAS 12
/** Metodo para eliminar el primer elemento de una lista */
public void eliminarPrimero() {
if (!estaVaca()){
inicio = inicio.sgte;
if (inicio == null)
fin = null;
else
inicio.anterior = null;
}
}
/** Metodo para eliminar el ultimo elemento de una lista */
public void eliminar

Ultimo() {
if (!estaVaca()){
fin = fin.anterior;
if (fin == null)
inicio = null;
else
fin.sgte = null;
}
}
public MiIterador elementos()
{ return new MiIterador(); }
...
}
Faltara hacer el iterador que incluya metodos para recorrer la lista en
sentido inverso.

También podría gustarte