Sesión 4 (Laboratorio) : Pilas y Colas 1.1. Implementación de Una Pila Con Listas Enlazadas Objetivo
Sesión 4 (Laboratorio) : Pilas y Colas 1.1. Implementación de Una Pila Con Listas Enlazadas Objetivo
Sesión 4 (Laboratorio) : Pilas y Colas 1.1. Implementación de Una Pila Con Listas Enlazadas Objetivo
Solución
La solución se puede ver en el siguiente listado:
/*
* LinkedStack.java
*
*/
public class LinkedStack {
class Node {
Object elem;
Node Next;
public Node(Object o) {
elem = o;
Next = null;
}
}
Node end;
int size;
public LinkedStack() {
end = null;
size = 0;
}
public void push(Object o) {
Node new_node = new Node(o);
if (end == null)
end = new_node;
else {
new_node.Next = end;
end = new_node;
}
size++;
}; // inserts an object onto the stack
public Object pop() {
if (end == null)
return null;
Object o = end.elem;
end = end.Next;
size--;
return o;
}// Gets the object from the stack
public boolean isEmpty() {
return (size == 0);
}
public int size() {
return size;
}
public Object end() {
if (end == null)
return null;
else
return end.elem;
}
} // class LinkedStack
Una lista se comporta como una cola si las inserciones las hacemos al final y las extracciones
las hacemos por el frente de la lista. También se las llama listas FIFO (First In First Out -
primero en entrar primero en salir)
Confeccionaremos un programa que permita administrar una lista tipo cola. Desarrollaremos
los métodos de insertar, extraer, vacia e imprimir.
Programa:
public class Cola {
class Nodo {
int info;
Nodo sig;
}
private Nodo raiz,fondo;
Cola() {
raiz=null;
fondo=null;
}
boolean vacia (){
if (raiz == null)
return true;
else
return false;
}
void insertar (int info)
{
Nodo nuevo;
nuevo = new Nodo ();
nuevo.info = info;
nuevo.sig = null;
if (vacia ()) {
raiz = nuevo;
fondo = nuevo;
} else {
fondo.sig = nuevo;
fondo = nuevo;
}
}
int extraer ()
{
if (!vacia ())
{
int informacion = raiz.info;
if (raiz == fondo){
raiz = null;
fondo = null;
} else {
raiz = raiz.sig;
}
return informacion;
} else
return Integer.MAX_VALUE;
}
public void imprimir() {
Nodo reco=raiz;
System.out.println("Listado de todos los elementos de la cola.");
while (reco!=null) {
System.out.print(reco.info+"-");
reco=reco.sig;
}
System.out.println();
}
Debemos enlazar el puntero sig del último nodo con el nodo recién creado:
fondo.sig = nuevo;
Y por último el puntero externo fondo debe apuntar al nodo apuntado por nuevo:
fondo = nuevo;
Con esto ya tenemos correctamente enlazados los nodos en la lista tipo cola. Recordar que el puntero
nuevo desaparece cuando se sale del método insertar, pero el nodo creado no se pierde porque queda
enlazado en la lista.
El funcionamiento del método extraer es similar al de la pila:
int extraer ()
{
if (!vacia ())
{
int informacion = raiz.info;
if (raiz == fondo){
raiz = null;
fondo = null;
} else {
raiz = raiz.sig;
}
return informacion;
} else
return Integer.MAX_VALUE;
}
Si la lista no está vacía guardamos en una variable local la información del primer nodo:
int informacion = raiz.info;
Para saber si hay un solo nodo verificamos si los dos punteros raiz y fondo apuntan a la misma dirección
de memoria:
if (raiz == fondo){
Luego hacemos:
raiz = null;
fondo = null;
En caso de haber 2 o más nodos debemos avanzar el puntero raiz al siguiente nodo:
raiz = raiz.sig;
Ya tenemos la lista correctamente enlazada (raiz apunta al primer nodo y fondo continúa apuntando al
último nodo)
42 - Estructuras dinámicas: Listas tipo Pila
Una lista se comporta como una pila si las inserciones y extracciones las hacemos por un mismo lado
de la lista. También se las llama listas LIFO (Last In First Out - último en entrar primero en salir)
Importante: Una pila al ser una lista puede almacenar en el campo de información cualquier tipo de
valor (int, char, float, vector de caracteres, un objeto, etc)
Para estudiar el mecanismo de utilización de una pila supondremos que en el campo de información
almacena un entero (para una fácil interpretación y codificación)
Inicialmente la PILA está vacía y decimos que el puntero raiz apunta a null (Si apunta a null decimos
que no tiene una dirección de memoria):
Luego de realizar la inserción la lista tipo pila queda de esta manera: un nodo con el valor 10 y raiz
apunta a dicho nodo. El puntero del nodo apunta a null ya que no hay otro nodo después de este.
Insertamos luego el valor 4: insertar(4)
Ahora el primer nodo de la pila es el que almacena el valor cuatro. raiz apunta a dicho nodo.
Recordemos que raiz es el puntero externo a la lista que almacena la dirección del primer nodo. El nodo
que acabamos de insertar en el campo puntero guarda la dirección del nodo que almacena el valor 10.
Ahora qué sucede si extraemos un nodo de la pila. ¿Cuál se extrae? Como sabemos en una pila se
extrae el último en entrar.
Al extraer de la pila tenemos: extraer()
class Nodo {
int info;
Nodo sig;
}
public Pila () {
raiz=null;
}
Por último queda enlazar el nodo que acabamos de crear al principio de la lista.
Si la lista está vacía debemos guardar en el campo sig del nodo el valor null para indicar que no hay
otro nodo después de este, y hacer que raiz apunte al nodo creado (sabemos si una lista esta vacía si
raiz almacena un null)
if (raiz==null)
{
nuevo.sig = null;
raiz = nuevo;
}
Gráficamente podemos observar que cuando indicamos raiz=nuevo, el puntero raiz guarda la dirección
del nodo apuntado por nuevo.
Tener en cuenta que cuando finaliza la ejecución del método el puntero nuevo desaparece, pero no el
nodo creado con el operador new.
En caso que la lista no esté vacía, el puntero sig del nodo que acabamos de crear debe apuntar al que
es hasta este momento el primer nodo, es decir al nodo que apunta raiz actualmente.
else
{
nuevo.sig = raiz;
raiz = nuevo;
}
Como primera actividad cargamos en el puntero sig del nodo apuntado por nuevo la dirección de raiz,
y posteriormente raiz apunta al nodo que acabamos de crear, que será ahora el primero de la lista.
Antes de los enlaces tenemos:
Luego de ejecutar la línea:
nuevo.sig = raiz;
Ahora tenemos:
El método extraer:
public int extraer ()
{
if (raiz!=null)
{
int informacion = raiz.info;
raiz = raiz.sig;
return informacion;
}
else
{
return Integer.MAX_VALUE;
}
}
El objetivo del método extraer es retornar la información del primer nodo y además borrarlo de la lista.
Si la lista no está vacía guardamos en una variable local la información del primer nodo:
int informacion = raiz.info;
Avanzamos raiz al segundo nodo de la lista, ya que borraremos el primero:
raiz = raiz.sig;
el nodo que previamente estaba apuntado por raiz es eliminado automáticamente por la máquina virtual
de Java, al no tener ninguna referencia.
Retornamos la información:
return informacion;
En caso de estar vacía la pila retornamos el número entero máximo y lo tomamos como código de error
(es decir nunca debemos guardar el entero mayor en la pila)
return Integer.MAX_VALUE;
Es muy importante entender gráficamente el manejo de las listas. La interpretación gráfica nos permitirá
plantear inicialmente las soluciones para el manejo de listas.
Por último expliquemos el método para recorrer una lista en forma completa e imprimir la información
de cada nodo:
public void imprimir() {
Nodo reco=raiz;
System.out.println("Listado de todos los elementos de la pila.");
while (reco!=null) {
System.out.print(reco.info+"-");
reco=reco.sig;
}
System.out.println();
}
Definimos un puntero auxiliar reco y hacemos que apunte al primer nodo de la lista:
Nodo reco=raiz;
Disponemos una estructura repetitiva que se repetirá mientras reco sea distinto a null. Dentro de la
estructura repetitiva hacemos que reco avance al siguiente nodo:
while (reco!=null) {
System.out.print(reco.info+"-");
reco=reco.sig;
}
Es muy importante entender la línea:
reco=reco.sig;
Estamos diciendo que reco almacena la dirección que tiene el puntero sig del nodo apuntado
actualmente por reco.
Gráficamente:
Al analizarse la condición:
while (reco!=null) {
se valúa en verdadero ya que reco apunta a un nodo y se vuelve a ejecutar la línea:
reco=reco.sig;
Ahora reco apunta al siguiente nodo:
La condición del while nuevamente se valúa en verdadera y avanza el puntero reco al siguiente nodo:
reco=reco.sig;
Ahora sí reco apunta a null y ha llegado el final de la lista (Recordar que el último nodo de la lista tiene
almacenado en el puntero sig el valor null, con el objetivo de saber que es el último nodo)
Para poder probar esta clase recordemos que debemos definir un objeto de la misma y llamar a sus
métodos:
public static void main(String[] ar) {
Pila pila1=new Pila();
pila1.insertar(10);
pila1.insertar(40);
pila1.insertar(3);
pila1.imprimir();
System.out.println("Extraemos de la pila:"+pila1.extraer());
pila1.imprimir();
}
Insertamos 3 enteros, luego imprimimos la pila, extraemos uno de la pila y finalmente imprimimos
nuevamente la pila.
Problema 2:
Agregar a la clase Pila un método que retorne la cantidad de nodos y otro que indique si esta vacía.
Programa:
public class Pila {
class Nodo {
int info;
Nodo sig;
}
Pila () {
raiz=null;
}