1. * Lista Simplemente enlazada.
*
*/
/**
*
* @author Pain
*/
//Clase Nodo. Utiliza el enlace llamado nodoDer o nodo derecho y el valor a
introducir.
public class Nodo {
Nodo nodoDer;
int dato;
public Nodo(int dato) {
this.dato = dato;
this.nodoDer = null;
}
}
/*
* Clase de Lista enlazada y metodos de agregar al final y borrar del mismo,
asi como mostrar tamaño y visualizar lista.
*
*/
import javax.swing.JOptionPane;
/**
*
* @author Pain
*/
public class ListaS {
private Nodo primero;
private Nodo ultimo;
private int tamano;
public ListaS() {
this.primero = null;
this.ultimo = null;
this.tamano = 0;
}
//Metodo utilizado para denotar que la lista se encuentra vacia.
public boolean siVacio() {
return (this.primero == null);
}
//Metodo para agregar al final de la lista.
public ListaS addLast(int dato) {
if(siVacio()) {
Nodo nuevo = new Nodo(dato);
primero = nuevo;
ultimo = nuevo;
nuevo.nodoDer = nuevo;
}
else {
Nodo nuevo = new Nodo(dato);
nuevo.nodoDer = null;
ultimo.nodoDer = nuevo;
ultimo = nuevo;
}
this.tamano++;
return this;
}
//Metodo para borrar al final de la lista.
public Nodo deleteLast() {
Nodo eliminar = null;
if(siVacio()) {
JOptionPane.showMessageDialog(null, "La lista se encuentra
vacia");
return null;
}
if(primero == ultimo) {
primero = null;
ultimo = null;
2. }
else {
Nodo actual = primero;
while(actual.nodoDer != ultimo) {
actual = actual.nodoDer;
}
eliminar = actual.nodoDer;
actual.nodoDer = null;
ultimo = actual;
}
this.tamano--;
return eliminar;
}
//Metodo que imprime el tamaño de la lista.
public void tamano() {
JOptionPane.showMessageDialog(null, "El tamaño es:n " + this.tamano);
}
//Metodo que imprime la lista y los valores ingresados.
public void imprimir() {
if(tamano != 0) {
Nodo temp = primero;
String str = "";
for(int i = 0; i < this.tamano; i++) {
str = str + temp.dato + "n";
temp = temp.nodoDer;
}
JOptionPane.showMessageDialog(null, str);
}
}
}
Listas Simples
Una lista simplemente ligada constituye una colección de elementos
llamados nodos. El orden entre estos se establece por medio de
punteros; es decir, direcciones o referencias a otros nodos. Un tipo
especial de lista simplemente ligada es la lista vacía. La figura F331 -
1 presenta la estructura de un nodo de una lista simplemente ligada.
En general, un nodo consta de dos partes:
1. Un campo INFORMACION que será del tipo de los datos que se
quiera almacenar en la lista.
2. Un campo LIGA, de tipo puntero, que se utiliza para establecer la
liga o el enlace con otro nodo de la lista. Si el nodo fuera el último de
la lista, este campo como valor NULO —vacio—. Al emplearse el
campo liga para relacionar dos, no será necesario almacenar
físicamente a los nodos en espacios contiguos.
3. En la figura F331-2 se presenta un ejemplo de una lista simplemente
ligada que almacena apellidos. El primer nodo de la lista es apuntado
por una variable P, de tipo apuntador —P almacena la dirección del
primer nodo—. El campo liga del último nodo de la tiene un valor
NULO, que indica que dicho nodo no apunta a ningún otro. El
apuntador al inicio de la lista es importante porque permite
posicionarnos en el primer nodo de la misma y tener acceso al resto
de los elementos. Si, por alguna razón, este apuntador se extraviara,
entonces perderemos toda la información almacenada en la lista. Por
otra parte, si la lista simplemente ligada estuviera vacía, entonces el
apuntador al tendrá el valor NULO.
Operaciones con listas simplemente ligadas
Las operaciones que pueden efectuarse en una lista simplemente
ligada son:
1. Recorrido de la lista.
2. Inserción de un elemento.
4. 3. Borrado de un elemento.
4. Búsqueda de un elemento.
Antes de analizar cada una de estas operaciones, se presentara un
algoritmo que permite crear una lista simplemente ligada, al incorporar
cada nuevo nodo al inicio.
Crea_Inicio
{Este algoritmo permite crear una lista simplemente ligada, agregando cada nuevo nodo al
inicio de la misma}
{P y Q son variables de tipo puntero. Los campos del nodo son INFO, que será del tipo de
datos que se quiera almacenar en la lista, y LIGA de tipo apuntador. P apunta al inicio de
la lista. RES es una variable de tipo entero}
1. Crear (P) {Se crea el primer nodo de la lista simplemente ligada}
2. Leer P^.INFO
3. Hacer P^.LIGA <- NULO
4. Escribir “¿Desea ingresar más nodos a la lista? Si: 1, No: 0”
5. Leer RES
6. Mientras (RES = 1) Repetir
Crear (Q)
Leer Q^.INFO
Hacer Q^.LIGA <- P y P <- Q
Escribir “¿Desea ingresar más nodos a la lista? Si: 1, No: 0”
Leer RES
7. {Fin del ciclo del paso 6}
Crea_final
{Este algoritmo permite crear una lista simplemente ligada, agregando cada nuevo final de
la misma}
{P, Q y T son variables de tipo apuntador. Los campos del nodo son INFO, que será del
tipo de datos que se quiera almacenar en la lista, y LIGA de tipo apuntador. P apunta al
inicio de lista. RES es una variable de tipo entero}
Crear (P) {Se crea el primer nodo de la lista)
Leer P^.INFO
Hacer P^.LIGA <- NULO y T <- P
Escribir “¿Desea ingresar mas nodos a la lista? Si: 1, No: 0”
Leer RES
Mientras (RES = 1) Repetir
Crear (Q)
Leer Q^.INFO
Hacer Q^.LIGA <- NULO, T^.LIGA <- Q y T<- Q { T apunta al
último nodo}
Escribir “¿Desea ingresar más nodos a la lista? Sí = 1, No = 0"
5. Leer RES
7. {Fin del ciclo del paso 6}
Recorrido de una lista simplemente ligada
La operación de recorrido en una lista simplemente ligada consiste en
visitar cada uno de los nodos que forman la lista. La visita puede
implicar una operación simple; por ejemplo, imprimir la información del
nodo, o una compleja, dependiendo del problema que se intente
resolver.
Para recorrer todos los nodos de una lista simplemente ligada se
comienza con el primero. Se toma el valor del campo LIGA de éste y
se avanza al segundo, y así sucesivamente hasta llegar al último
nodo, cuyo campo LIGA tiene el valor NULO. En general, la dirección
de un nodo, excepto el primero, está dada por el campo LIGA de su
predecesor.
Recorre_Iterativo (P)
{Éste algoritmo recorre una lista cuyo primer nodo esta apuntado por P}
{Q es una variable de tipo apuntador. INFO y LIGA son los campos de cada nodo de la
lista}
1. Hacer Q <- P
2. Mientras (Q ≠ NULO) Repetir
Escribir Q^.INFO
Hacer Q <- Q^.LIGA {Apunta al siguiente nodo de la lista}
3. {Fin del ciclo del paso 2}
Las listas se pueden manejar fácilmente con procesos recursivos. El
algoritmo siguiente constituye una versión recursiva para recorrer una
lista simplemente ligada.
Recorre_recursivo (F)
{Este algoritmo recorre una lista simplemente ligada en forma recursiva. P es un apuntador
al nodo que se va a visitar. La primera vez trae la dirección del primer nodo de la lista}
{INFO y LIGA son los campos de cada nodo de la lista}
1. Si P ≠ NULO entonces
Escribir P^.INFO
6. Llamar a Recorre_recursivo con P^.LIGA {Llamada recursiva con el
apuntador al siguiente nodo de la lista}
2, {Fin del condicional del paso 1}
Inserción en listas simplemente ligadas
La operación de inserción en listas simplemente ligadas consiste en
agregar un nuevo nodo a la lista. Sin embargo, dependiendo de la
posición en la que se deba insertar el nodo, se pueden presentar
diferentes casos, como los que se señalan a continuación
• Insertar un nodo al inicio de la lista.
• Insertar un nodo al final de la lista.
• Insertar un nodo antes que otro cuya información es X.
• Insertar un nodo después que otro cuya información es X.
Siendo evaluados los dos primeros, por ser los más comunes.
a) Inserción al inicio de una lista simplemente ligada
Inserta_Inicio(P, DATO)
{Este algoritmo inserta al inicio de una lista simplemente ligada. P es el apuntador al
primer nodo de la misma, y DATO es la información que se almacenará en el nuevo nodo}
{Q es una variable de tipo apuntador, INFO y LIGA son los campos de cada nodo de la
lista}
1. Crea (Q)
2. Hacer Q^.INFO <- DATO, Q^.LIGA <- P y P <- Q
b) Inserción al final de una lista simplemente ligada
Inserta_Final(P, DATO)
Este algoritmo inserta un nodo al final de una lista simplemente liga. P es el apuntador al
primer nodo de la lista, y DATO es la información que se almacenará en el nuevo nodo}
{Q y T son variables de tipo apuntador, INFO y LIGA son los campos de cada nodo de la
lista}
1. Hacer T <- P
2. Mientras ( T^.LIGA ≠ NULO ) repetir
{Recorre la lista hasta llegar al último elemento}
Hacer T <- T^.LIGA
3. {Fin del ciclo del paso 2}
7. 4. Crea (Q)
2. Hacer Q^.INFO <- DATO, Q^.LIGA <- NULO y T^.LIGA <- Q
Eliminación en listas simplemente ligadas
La operación de eliminación en las listas simplemente ligadas
consiste en eliminar un nodo de la lista y liberar el espacio de memoria
correspondiente. Dependiendo de la posición en la que éste se
encuentre, se pueden presentar diferentes casos, como los que se
señalan a continuación:
• Eliminar el primer nodo.
• Eliminar el último nodo.
• Eliminar un nodo con información X
• Eliminar el nodo anterior al nodo con información X
• Eliminar el nodo posterior al nodo con información X
Cabe destacar que en los algoritmos que se presentarán a
continuación no se considera que la lista esté vacía. Esta condición se
puede evaluar fácilmente al inicio del algoritmo o bien en el programa
principal.
Por ser los más comunes, se evaluaran los primeros tres algoritmos.
Eliminar el primer nodo de la lista simplemente ligada.
Elimina_Inicio(P)
{Este algoritmo permite eliminar el primer elemento de una lista simplemente ligada. P es
el apuntador al primer elemento de la lista} {Q es una variable de tipo a puntador, INFO y
LIGA son los campos de los nodos de la lista}
1. Hacer Q <- P
{Si la lista tuviera sólo un elemento entonces a P se le asignaría NULO, que es el valor
de Q^.LIGA. En caso contrario, queda con la dirección del siguiente elemento}
2. Hacer P <- Q^.LIGA {Redefine el puntero al inicio de la lista}
3. Quitar(Q)
Elimina el último nodo de la lista simplemente ligada
Elimina_Ultimo(P)
{Este algoritmo elimina el último nodo de la una lista simplemente ligada. P es el
apuntador al primer nodo de la lista}
{Q y P son variables de tipo apuntador. INFO y LIGA son los campos de los nodos de la
lista}
1. Hacer Q <- P
8. 2. Si (P^.LIGA = NULO) {Se verifica si la lista tiene sólo un nodo}
entonces
Hacer P <- NULO
si no
2.2. Mientras (Q^.LIGA ≠ NULO) repetir
Hacer T <- Q y Q <- Q^.LIGA
2.3. {Fin del ciclo del paso 2.1}
3. {Fin del condicionante del paso 2}
4. Quitar(Q)
Eliminar un nodo con información X de una lista simplemente
ligada
Elimina_X
{Este algoritmo permite elimina un nodo con información X de una lista simplemente
ligada. P es el apuntador al primer nodo de la lista}
{Q y T son variables de tipo apuntador. BAND es una variable de tipo entero. INFO y LIGA
son los campos de los nodos de la lista}
1. Hacer Q <- P y BAND <- 1
2. Mientras ((Q^.INFO ≠ X ) y (BAND = 1)) repetir
2.1 si Q^.LIGA ≠ NULO
entonces
Hacer T <- Q y Q <- Q^.LIGA
si no
Hacer BAND <- 0
2.2 {Fin del condicionante del paso 2.1}
3. {Fin del ciclo del paso 2}
4. Si (BAND = 0)
entonces
Escribir “El elemento con información X no se encuentra en
la lista”
si no
4.1 Si (P = Q) {Se verifica si el elemento a eliminar es el primero}
Entonces
Hacer P <- Q^.LIGA
si no
Hacer T^.LIGA <- Q^.LIGA
4.2 {Fin del condicional del paso 4.1}
Quitar (Q)
5. {Fin del condicional del paso 4}
Búsqueda en listas simplemente ligadas
9. La operación de búsquedas de un elemento en una lista simplemente
ligada es muy fácil de realizar, aunque infidente ya que se lleva a cabo
de forma secuencial. Se debe ir recorriendo los nodos hasta encontrar
el que estamos buscando o hasta que se llegue al final de la lista. El
algoritmo es similar a los que se desarrollaron para recorrer una lista
en forma iterativa o recursiva.
Al igual que en el caso de las operaciones vistas anteriormente,
existen deficiencias en los algoritmos si las listas se encuentran
ordenadas o desordenadas. Se comenzará, en primer término, con el
algoritmo de búsqueda par listas simplemente ligadas que se
encuentran desordenadas.
Búsqueda_Desordenada(P,X)
{Este algoritmo permite buscar el elemento con la información X en
una lista simplemente ligada que se encuentra desordenada. P es una
variable de tipo apuntador, señalando al primer nodo}
{Q es una variable tipo apuntador. INFO y LIGA son campos de los
nodos de la lista}
1. Hacer Q <- P
2. Mientras ((Q ≠ NULO) y (Q^.INFO ≠ X)) repetir
Hacer Q <- Q^.LIGA
3. {Fin del ciclo del paso 2}
4. Si (Q = NULO)
entonces
Escribir “El elemento no se encuentra en la lista”
si no
Escribir “El elemento si se encuentra en la lista”
5. {Fin del condicionante del paso 4}
Es importante destacar que con una simple modificación en la
codificación del ciclo del paso 2 se adapte este algoritmo para la
búsqueda de elementos en la lista simplemente ligada que se
encuentran ordenados. A continuación se presentan el algoritmo de
búsqueda en listas simplemente ligadas ordenadas en forma
ascendente.
Búsqueda_Ordenada(P,X)
{Este algoritmo permite buscar el elemento con la información X en una lista simplemente
ligada que se encuentra ordenada de forma ascendente. P es una variable de tipo
10. apuntador, señalando al primer nodo}
{Q es una variable tipo apuntador. INFO y LIGA son campos de los nodos de la lista}
1. Hacer Q <- P
2. Mientras ((Q ≠ NULO) y (Q^.INFO < X)) repetir
Hacer Q <- Q^.LIGA
3. {Fin del ciclo del paso 2}
4. Si ((Q = NULO) o (Q^.INFO > X))
entonces
Escribir “El elemento no se encuentra en la lista”
si no
Escribir “El elemento si se encuentra en la lista”
5. {Fin del condicionante del paso 4}
Todos los algoritmos presentados tanto en la búsqueda, inserción y
eliminación se pueden implementar de forma recursiva. A continuación
se muestra una versión recursiva del algoritmo de búsqueda
desordenada.
Busqueda_Recursiva(P,X)
{Este algoritmo permite buscar recursivamente a un elemento con
información X en una lista simplemente ligada que se encuentre
desordenad. P es el apuntador al primer nodo de la lista}
1. Si (P ≠ NULO)
entonces
1.1 Si (P^.INFO = X)
entonces
Escribimos “El elemento se encuentra en la lista”
si no
Llamar a Busqueda_Recursivo con P^.LIGA y X
1.2 {Fin del condicionante del paso 1.1}
si no
Escribir “El elemento no se encuentra en la lista";
2. {Fin del condicionante del paso 1}
Listas ligadas
En las secciones anteriores se contemplaron diferentes estructuras estáticas en dónde la
manipulación de datos es a través de posiciones localizadas secuencialmente. Para de
clarar estas estructuras se debía definir un tamaño determinado el cual no podía
modificarse posteriormente. Esto puede ser un problema en el caso de que:
11. • no sepamos de antemano el tamaño requerido para nuestra aplicación
• hay una gran cantidad de operaciones y manipulaciones de los datos dentro de
las estructuras
En estos casos es generalmente m&a acute;s conveniente utilizar estructuras dinámicas,
es decir, las cuales pueden aumentar o disminuir de tamaño de acuerdo a los
requerimientos específicos del procedimiento. Así se resuelve el problema de no saber
el tama&ntild e;o exacto desde un principio y las manipulaciones de datos se pueden
hacer de una manera mas rápida y eficiente.
Una lista ligada es entonces un grupo de datos organizados secuencialmente, pero a
diferencia de los arreglos, la organización no esta dada implícitamente por su posición
en el arreglo. En una lista ligada cada elemento es un nodo que contiene el dato y
además una liga al siguiente dato. Estas ligas son simplemente variables que contienen
la(s) dirección(es) de los datos contiguos o relacionados.
Para manejar una lista es necesario contar con un apuntador al primer elemento de la
lista "head" .
Las ventajas de las listas ligadas son que:
• Permiten que sus tamaños cambien durante la ejecución del programa
• Proveen una major flexibilidad en el manejo de los datos.
Este principio de listas ligadas se puede aplicar a cualquiera de los conceptos de
estructura de datos vistos anteriormente: arreglos, colas y pilas . Es decir, las
operaciones de altas, bajas y cambios, así como búsquedas y ordenamientos se tendrán
que adaptar en la cuestión del manejo de localidades únicamente.
Listas ligadas sencillas
Una lista ligada sencilla es un grupo de datos en dónde cada dato contiene además un
apuntador hacia el siguiente dato en la lista, es decir, una liga hacia el siguiente dato.
Los siguientes algoritmos fueron tomados de "Estructuras de Datos", Cairó - Guardati,
2a. Ed., McGraw Hill, 2002.
Algoritmo 5.1
CREAINICIO(P)
{Este algoritmo crea una lista, agregando cada nuevo nodo al inicio de
la misma}
{ P y Q son variables de tipo puntero. P apuntará al inicio de la
lista}
1. CREA (P) {Crea el primer nodo de la lista}
2. Leer P->INFORMACIÓN
3. Hacer P->LIGA=NIL
4. Repetir
CREA (Q)
Leer Q->INFORMACIÓN
Hacer Q->LIGA= P y P = Q
5. Hasta (que ya no haya información)
12. Algoritmo 5.2
CREAFINAL(P)
{Este algoritmo crea una lista, agregando cada nuevo nodo al final de
la misma}
{P y Q son variables de tipo puntero. P apuntará al inicio de la
lista}
1. CREA (P) {Crea el primer nodo de la lista}
2. Leer P->INFORMACIÓN
3. Hacer P->LIGA=NIL y T=P
4. Repetir
CREA (Q)
Leer Q->INFORMACIÓN
Hacer Q->LIGA=NIL, T->LIGA=Q y T=Q
5. Hasta (que ya no haya información)
Para poder dar de alta un dato en una lista ligada sencilla es necesario recorrer la lista
nodo por nodo hasta encontrar la posición adecuada. Se crea un nuevo nodo, se inserta
el dato y se actualizan las ligas del nodo nuevo y del anterior para intercalar el nuevo
nodo en la lista.
Algoritmo 5.3
RECORREITERATIVO(P)
{Este algoritmo recorre una lista cuyo primer nodo está apuntado por
P}
{Q es una variable de tipo puntero}
1. Hacer Q = P
2. Repetir mientras Q =! NIL
Escribir Q->INFORMACUÓN
Hacer Q=Q->LIGA {Apunta al siguiente nodo de la lista}
3. {Fin del ciclo del paso 2}
Algoritmo 5.4
RECORRECURSIVO(P)
{Este algoritmo recorre una lista recursivamente. P es el apuntador
al nodo a visitar}
1. Si P =! NIL entonces
Escribir P->INFORMACIÓN
Llamar a RECORRECURSIVO con P->LIGA
{Llamada recursiva con el apuntador al siguiente nodo
de la lista}
2. {Fin del condicional del paso 1}
Algoritmo 5.6
INSERTAFINAL(P)
{Este algoritmo inserta un nodo al final de la lista. P es el
apuntador al primer nodo
de la lista, y DATO es la información que se almacenará en el nuevo
nodo}
{Q y T son variables de tipo puntero}
13. 1. Hacer T= P
2. Repetir mientras T ->Liga =! NIL
{Recorre la lista hasta llegar al último elemento}
Hacer T=T->LIGA
3. {Fin del ciclo del paso 2}
4. CREA (Q)
5. Hacer Q->INFORMACIÓN =DATO, Q->LIGA =NIL y T ->LIGA =Q
Algoritmo 5.7
INSERTANTES ( P, DATO, REF )
{Este algoritmo inserta un nodo dado como referencia, REF. P es el
apuntador al
primer nodo de la lista, y DATO es la información que se almacenará en
el nuevo nodo}
{Q, X y T son variables de tipo puntero, BAND es una variable de tipo
booleano}
1. Hacer Q= P y BAND= VERDADERO
2. Repetir mientras (Q->INFORMACIÓN =! REF) y (BAND =
VERDADERO)
2.1 Si Q -> LIGA =! NIL
Entonces
Hacer T= Q y Q= Q-> LIGA
Si no
Hacer BAND = FALSO
2.2 {Fin del condicional del paso 2.1}
3. {Fin del ciclo del paso 2}
4. Si BAND = VERDADERO entonces
CREA(X)
Hacer X->INFORMACIÓN = DATO
4.1 Si P = Q {Es el primer nodo}
Entonces
Hacer X ->LIGA = P y P = X
Si no
Hacer T ->LIGA =X y X ->LIGA = Q
4.2 {Fin del condicional del paso 4.1}
5. {Fin del condicional del paso 4}
Algoritmo 5.9
ELIMINAPRIMERO(P)
{Este algoritmo borra el primer elemento de una lista. P es el
apuntador al primer nodo de la lista}
{Q es una variable de tipo puntero}
1. Hacer Q = P
2. Si Q -> LIGA =! NIL {Verifica si la lista tiene sólo un
nodo}
Entonces
Hacer P= Q-> LIGA {Redefine el puntero al
inicio}
Si no
Hacer P = NIL
3. {Fin del condicional del paso2}
4. QUITA(Q)
14. Algoritmo 5.10
ELIMINAÚLTIMO(P)
{Este algoritmo borra el último elemento de una lista. P es el
apuntador al primer nodo de la lista}
{Q y T son variables de tipo puntero}
1. Si P -> LIGA = NIL {Verifica si la lista tiene sólo un
elemento}
Entonces
QUITA(P)
Hacer P = NIL
Si no
Hacer Q = P
1.1 Repetir mientras ( Q->LIGA =! NIL)
Hacer T=Q y Q = Q -> LIGA
1.2 {Fin del ciclo del paso 1.1}
Hacer T -> LIGA = NIL
QUITA(Q)
2. {Fin del condicional del paso 1}
Algoritmo 5.11
ELIMINAX( P, X )
{Este algoritmo elimina un nodo con información X de una lista. P es
el apuntador al primer nodo de la lista}
{Q y T son variables de tipo puntero. BAND es una variable de tipo
booleano}
1. Hacer Q = P y BAND= VERDADERO
2. Repetir mientras (Q->INFORMACIÓN =! X) y (BAND =
VERDADERO)
2.1 Si Q ->LIGA =! NIL
Entonces
Hacer T = Q y Q = Q -> LIGA
Si no
Hacer BAND = FALSO
2.2 {Fin del condicional del paso 2.1}
3. {Fin del ciclo del paso 2}
4. Si BAND = FALSO
Entonces
Escribir ”El elemento no fue encontrado”
Si no
4.1 SI P = Q {Verifica si el elemento a eliminar
es el primero}
Entonces
Hacer P = Q->LIGA
Si no
Hacer T -> LIGA=Q-> LIGA
4.2 {Fin del condicional del paso 4.1}
QUITA(Q)
5. {Fin del condicional del paso 4}
Algoritmo 5.15
BUSCARRECURSIVO(P,X)
15. {Este algoritmo busca recursivamente al elemento con información X en
una lista que se encuentra desordenada. P es el apuntador del nodo a
visitar}
1. Si ( P =! NIL)
Entonces
1.1 Si ( P ->INFORMACIÓN = X )
Entonces
Escribir “El elemento se encuentra en la
lista”
Si no
Llamar a BUSCARRECURSIVO con P -> LIGA
y X
1.2 {Fin del condicional del paso 1.1}
Si no
Escribir “El elemento no se encuentra en
la lista”
2. {Fin del condicional del paso 1}