Resumen Listas Enlazadas - Departamento de Computación

Anuncio
Resumen Listas Enlazadas
Estructuras Dinámicas de Datos
Las estructuras dinámicas de datos son estructuras que crecen a medida que se ejecuta un programa.
Al contrario de un arreglo que contiene un espacio de memoria determinado para almacenar un
número fijo de elementos, asignado al inicio de un programa, una estructura dinámica de datos se
amplia y contrae durante la ejecución de un programa según sea la necesidad de agregar o eliminar
elementos.
Una estructura dinámica de datos es una colección de elementos llamados nodos que están
conectados entre sí por enlaces de apuntador (referencias a objetos). Un nodo (Figura 1) es una
estructura de datos que contiene dos campos, un campo que almacena el dato (dato primitivo u
objeto) y otro campo denominado enlace que almacena la referencia al próximo nodo.
dato
enlace
Figura 1. Estructura de un nodo
Implementación de una clase Nodo
Con campo de dato primitivo int
Con campo de dato genérico Object
public class Nodo {
public class Nodo {
public int dato;
public Nodo enlace;
public Object dato;
public Nodo enlace;
public Nodo(int d) {
dato = d;
enlace = null;
}
public Nodo(int d, Nodo e) {
dato = d;
enlace = e;
}
public Nodo(Object d) {
dato = d;
enlace = null;
}
public Nodo(Object d, Nodo e) {
dato = d;
enlace = e;
}
}
}
Listas enlazadas
Una lista enlazada (Figura 2) es un conjunto lineal de objetos de una clase llamada Nodo. Una lista
enlazada se accesa por medio de una referencia al primer nodo de la lista, generalmente llamado cab.
Los nodos subsiguientes se accesan por medio del campo de enlace que esta almacenado en cada
nodo. Por convención el enlace del último nodo de la lista se establece a null para marcar el final de
la lista.
cab
Referencia al
null
dato
enlace
dato
enlace
dato
enlace
primer nodo
Figura 2. Lista enlazada
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Listas Enlazadas
2
En una lista enlazada, los datos se almacenan dinámicamente y cada nodo se crea conforme se
necesita. Las listas de datos pueden almacenarse en arreglos, pero las listas enlazadas proporcionan
varias ventajas. Una lista enlazada es adecuada cuando es impredecible el número de datos a
almacenar en la estructura. Las listas enlazadas pueden mantenerse de forma ordenada simplemente
insertando cada nuevo dato en el punto adecuado de la lista sin necesidad de mover los elementos
existentes en la lista. Las listas enlazadas tienen la desventaja que por cada dato de la lista requiere
de un espacio de memoria para el enlace al próximo dato, adicionalmente la asignación dinámica de
memoria incurre en la sobrecarga de llamadas a función a diferencia del acceso a un elemento de un
arreglo, que se realiza directamente calculando la posición del elemento con respecto a la dirección
de inicio del arreglo.
Clasificación
Las listas enlazadas se clasifican en:
Listas enlazadas simples, doblemente enlazadas, circulares simplemente enlazadas y circulares
doblemente enlazadas.
Implementación de una clase Lista
public class Lista {
private Nodo cab;
public Lista() {
cab = null;
}
public Nodo getCab(){
return cab;
}
public boolean vacia(){
return cab == null;
}
public String toString(){
String s = "";
Nodo aux = cab;
while (aux != null){
s+= aux.dato+"\t";
aux = aux.enlace;
}
return s;
}
public void visualizar(){
System.out.println("Lista\n"+this);
}
Operaciones básicas en una lista enlazada:
ƒ
Insertar un nodo en la cabecera de la lista
public Lista insertarCab(int d){
cab = new Nodo(d,cab);
return this;
}
Se crea un nuevo nodo con el enlace apuntando
al elemento apuntado por cab (el primero de la
lista). A cab se le asigna la referencia al nuevo
nodo creado.
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Listas Enlazadas
ƒ
Determinar la referencia al último nodo de la lista
/* Busca y retorna la referencia al último
nodo de la lista, si la lista esta
vacía retorna null*/
public Nodo ultimoNodo(){
Nodo aux = cab;
Nodo ultimo = null;
while (aux != null){
ultimo = aux;
aux = aux.enlace;
}
return ultimo;
}
ƒ
aux se utiliza para recorrer la lista y
ultimo se utiliza para guardar la
referencia al nodo anterior al
referenciado por aux. Retorna null si
la lista esta vacía.
Insertar un nuevo nodo al final de la lista.
/* Inserta un nodo al final de la lista */
public Lista insertarFinal(int d){
if (vacia())
insertarCab(d);
else{
Nodo ultimo = ultimoNodo();
ultimo.enlace = new Nodo(d);
}
return this;
}
ƒ
3
Si la lista esta vacía inserta el dato d en
la cabecera de la lista.
Sino crea un nuevo nodo con enlace a
null y lo enlaza con el último nodo de
la lista.
Accesar un dato almacenado en un nodo específico.
/* Busca y retorna la referencia al nodo
que almacena un valor d */
public Nodo buscarDato(int d) throws Exception{
if (vacia())
throw new Exception("Lista vacía");
else{
Nodo aux = cab;
while((aux != null) && (aux.dato!= d))
aux = aux.enlace;
return aux;
}
}
Si la lista esta vacía lanza una
excepción.
aux se utiliza para recorrer la lista
e ir accesando cada campo dato
para compararlo con d.
Sino encuentra el dato d, retorna
null.
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Listas Enlazadas
ƒ
4
Eliminar un nodo existente que contiene una información en particular.
/* Elimina el nodo cuyo dato
sea igual a un valor d que
recibe como parámetro*/
public Lista eliminarDato(int d) throws Exception{
if (vacia())
throw new Exception("Lista vacía");
else{
Nodo b = buscarDato(d);
if (b != null){
Nodo a = nodoAnterior(d);
if (a == null)
cab = cab.enlace;
else
a.enlace = b.enlace;
}
return this;
}
}
Si la lista esta vacía lanza
una excepción.
a se utiliza para almacenar
la referencia al nodo anterior
y b para almacenar la
referencia al nodo que
almacena d.
Si d no existe (b == null)
no hace nada.
Si encuentra el dato d,
determina la referencia al
nodo anterior a d, si la
referencia al anterior es
null significa que d esta en
el primer nodo de la lista.
ƒ
Obtener la referencia al nodo anterior a un nodo que almacena un valor d.
/* Busca y retorna la referencia al nodo
anterior al nodo que almacena un valor d*/
public Nodo nodoAnterior(int d) throws Exception{
if (vacia())
throw new Exception("Lista vacía");
else{
Nodo anterior = null;
Nodo aux = cab;
while((aux != null) && (aux.dato!= d)){
anterior = aux;
aux = aux.enlace;
}
return anterior;
}
}
Si la lista esta vacía lanza
una excepción.
aux se utiliza para recorrer
la lista y anterior se utiliza
para guardar la referencia al
nodo anterior al referenciado
por aux.
Si d se encuentra en el
primer nodo retorna null.
Si d no existe retorna la
referencia al último nodo de
la lista.
Este método se puede modificar para que retorne una excepción cuando d no se encuentre en la lista.
public Nodo nodoAnterior(int d) throws Exception{
if (vacia())
throw new Exception("Lista vacía");
else{
if (buscarDato(d)==null)
throw new Exception(d + "no encontrado");
else{
Nodo anterior = null;
Nodo aux = cab;
while((aux != null) && (aux.dato!= d)){
anterior = aux;
aux = aux.enlace;
}
return anterior;
}
}}
De este modo si
retorna null, es
porque el dato d
esta en el primer
nodo de la lista.
Sino, retorna la
referencia del nodo
anterior a d.
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Listas Enlazadas
ƒ
5
Insertar un dato v en una posición anterior a un nodo que almacena un dato d.
/* Inserta un nodo con dato v antes de un nodo cuyo
dato sea igual a un valor d que recibe como
parámetro*/
public Lista insertarAntes(int v, int d)
throws Exception{
if (vacia())
insertarCab(v);
else{
Nodo b = buscarDato(d);
if (b != null){
Nodo a = nodoAnterior(d);
if (a == null)
insertarCab(v);
else
a.enlace = new Nodo(v,a.enlace);
}
}
return this;
}
a se utiliza para
almacenar la referencia
al nodo anterior y b para
almacenar la referencia
al nodo que almacena d.
Si la lista esta vacía,
inserta v en la cabecera.
Sino busca determina el
valor de b.
Si lo encuentra,
determina el valor de a.
Si a==null, es porque d
es el primero de la lista,
entones lo inserta en la
cabecera. Sino crea un
nuevo nodo y lo enlaza.
Si d no existe no inserta
v.
ƒ
Insertar un dato d manteniendo la lista ordenada ascendentemente.
/*
* Inserta un dato d manteniendo la lista ordenada
* en orden ascendente
* si la lista esta vacía, lo inserta en la cabecera
*/
public Lista insertarOrd(int d){
if (vacia())
insertarCab(d);
else{
Nodo aux = cab;
Nodo anterior = null;
while((aux != null) && (d > aux.dato)){
anterior = aux;
aux = aux.enlace;
}
if (anterior == null)
insertarCab(d);
else
anterior.enlace = new Nodo(d,anterior.enlace);
}
return this;
}
Si la lista está vacía
inserta d en la
cabecera.
Sino determina la
posición donde
debe insertar d
para mantener el
orden.
Para ello, determina
la referencia al
nodo anterior a
donde debe
insertar.
Si d es menor que
el dato del primer
nodo
(anterior == null)
inserta d en la
cabecera.
Sino crea un nuevo
nodo con d y lo
enlaza
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Listas Enlazadas
6
Pilas
Una pila (stack) es un tipo especial de una lista enlazada, ya que los nuevos nodos sólo pueden
agregarse o eliminarse por la cabecera de la lista, generalmente llamado tope o cima de la pila. Se
caracteriza por ser una estructura LIFO (último en entrar primero en salir, Last Input First Output).
Implementación de una clase Pila
import listasEnlazadas.*;
//para usar Nodo de int
public class Pila {
private Nodo tope;
public Pila() {
tope = null;
}
public Nodo getTope(){
return tope;
}
Solo se permite el
acceso al elemento
ubicado en el tope de
la Pila tanto para
eliminarlo (pop) como
para agregarlo
(push).
La referencia al
primer Nodo es tope.
public boolean vacia(){
return tope == null;
}
/** agrega un dato en el tope de la pila*/
public Pila push(int d){
tope = new Nodo(d, tope);
return this;
}
/** retira el dato del tope de la pila*/
public Pila pop() throws Exception{
if (vacia())
throw new Exception("Pila vacía");
else
tope = tope.enlace;
return this;
}
/** retorna el dato ubicado en el tope de la pila*/
public int info() throws Exception{
if (vacia())
throw new Exception("Pila vacía");
else
return tope.dato;
}
public String toString(){
String s = "";
Nodo aux = tope;
while (aux != null){
s+= aux.dato + "\n";
aux = aux.enlace;
}
return s;
}}
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Listas Enlazadas
7
Colas
Una cola (queue) es similar a una cola de personas para comprar entradas al cine, la primera persona
que está en la cola, es la primera en ser atendida, las nuevas personas que lleguen deben agregarse al
final de la cola. En una cola implementada con una lista enlazada, los nodos de una cola se eliminan
solamente desde el inicio de la lista y se insertan solamente al final de la lista. Se caracteriza por ser
una estructura FIFO (primero en entrar primero en salir, First Input First Output).
Implementación de una clase Cola
import listasEnlazadas.*;
//para usar Nodo de int
public class Cola {
private Nodo primero;
private Nodo ultimo;
public Cola() {
primero = null;
ultimo = null;
}
public boolean vacia(){
return primero == null;
}
/* agrega un elemento al final de la cola */
public Cola entrar(int d){
if (vacia()){
primero = new Nodo(d);
ultimo = primero;
}else{
ultimo.enlace = new Nodo(d);
ultimo = ultimo.enlace;
}
return this;
}
Se utilizan dos
apuntadores:
primero que referencia el
primer nodo de la lista y
facilita las operaciones de
acceso al primer elemento
de la cola.
ultimo que referencia al
ultimo nodo de la lista y
facilita las operaciones de
acceso al ultimo elemento
de la cola.
Es muy importante
mantener actualizados
estos apuntadores, cada
vez que se agregan o
extraen elementos de una
Cola.
/* elimina un elemento ubicado al inicio de la cola*/
public Cola salir(int d) throws Exception{
if (vacia())
throw new Exception("Cola vacía");
else{
primero = primero.enlace;
if (primero == null) ultimo = null;
}
return this;
}
public String toString(){
String s = "";
Nodo aux = primero;
while (aux != null){
s+= aux.dato + "\t";
aux = aux.enlace;
}
return s;
}
}
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Listas Enlazadas
8
Ejercicios propuestos
1. Desarrollar un programa que cree una lista enlazada de 10 caracteres y luego cree un segundo
objeto de lista, que contenga una copia de la primera lista, pero en orden inverso.
2. Escriba un programa que dada una línea de texto utilice un objeto de pila para imprimir la pila en
orden inverso.
3. Agregar un método concatenar a la clase Lista para concatenar dos Listas.
public Lista concatenar(Lista obj)
Por ejemplo:
Lista b
Lista a
cab
10
12
14
null
cab
100
Lista concatenada
200
null
cab
10
12
14
100
200
null
4. Agregar un método a la clase Lista que modifique el campo dato del n-ésimo nodo de una lista
enlazada por un valor dado x.
5. Agregar un método a la clase Lista que realice la inserción contigua a la izquierda del n-ésimo
nodo de una lista enlazada y un método que realice la inserción contigua a la derecha del n-ésimo
nodo.
6. Dados un conjunto de puntos pertenecientes a un plano. Desarrollar un programa que cree una
lista de objetos Point y obtenga en una nueva Lista la distancia existente entre cada punto
(Point) de la lista y el primer punto (Point) almacenado en la lista. El primer nodo de la nueva
Lista almacenará cero, porque es la distancia con respecto a sí mismo. Utilice la clase Lista del
package listaGenerica y utilice el método distance de la clase Point para calcular la distancia
entre puntos.
7. Se tiene almacenada cada palabra de un texto en una lista enlazada. Determinar la frecuencia de
aparición de cada una de las palabras en el texto. Por ejemplo, para el texto: los libros los
llevo mañana los compro mañana. Se tiene que la frecuencia de aparición de cada palabra es:
los
3
nnn
libros
1
nnn
llevo
1
nnn
mañana
2
nnn
compro
1
null
Universidad de Carabobo. Facultad de Ingeniería. Departamento de Computación. Computación Avanzada. 1-2006.
Descargar