Sie sind auf Seite 1von 48

Artculo

InicioArtculoLenguajes orientados a objetoJavaJ2EE

votar!

20

Estructuras de Datos y Algoritmos en Java

Listas Enlazadas o Lista de Enlace Simple o Los Algoritmos de Concatenacin e Inversin o Lista Doblemente Enlazada Algoritmo de Insercin-Ordenada o Lista de Enlace Circular o Listas Enlazadas frente a Arrays

Listas Enlazadas
Adems de los arrays, otra de las estructuras de datos muy utilizada es la lista enlazada. Esta estructura implica cuatro conceptos: clase auto-refenciada, nodo, campo de enlace y enlace.

Clase auto-referenciada: una clase con al menos un campo cuyo tipo de referencia es el nombre de la clase:

class Employee { private int empno; private String name; private double salary; public Employee next; // Other members } Employee es una clase auto-referenciada porque su campo next tiene el tipo Employee.
Nodo: un objeto creado desde una clase auto-referenciada. Campo de enlace: un campo cuyo tipo de referencia es el nombre de la clase. En el fragmento de cdigo anterior, next es un campo de enlace. Por el contrario, empno, name, y salary son campos no de enlace. Enlace: la referencia a un campo de enlace. En el fragmento de cdigo anterior, la referencia next a un nodo Employee es un enlace.

Los cuatro conceptos de arriba nos llevan a la siguiente definicin: una lista enlazada es una secuencia de nodos que se interconectan mediante sus campos de enlace. En ciencia de la computacin se utiliza una notacin especial para ilustrar las listas enlazadas. En la siguiente imagen aparece una variante de esta notacin que utilizar a lo largo de esta seccin:

La figura anterior presenta tres nodos: A, B y C. Cada nodo se divide en reas de contenido (en naranja) y una o ms reas de enlace (en verde). Las reas de contenido representan todos los campos que no son enlaces, y cada rea de enlace representa un campo de enlace. Las reas de enlace de A y C tienen unas flechas para indicar que referencian a otro nodo del mismo tipo (o subtipo). El nico rea de enlace de B incorpora una X para indicar una referencia nula. En otras palabras, B no est conectado a ningn otro nodo. Aunque se pueden crear muchos tipos de listas enlazadas, las tres variantes ms populares son la lista de enlace simple, la lista doblemente enlazada y la lista enlazada circular. Exploremos esas variantes, empezando con la lista enlazada.

Lista de Enlace Simple


Una lista de enlace simple es una lista enlazada de nodos, donde cada nodo tiene un nico campo de enlace. Una variable de referencia contiene una referencia al primer nodo, cada nodo (excepto el ltimo) enlaza con el nodo siguiente, y el enlace del ltimo nodo contiene null para indicar el final de la lista. Aunque normalmente a la variable de referencia se la suele llamar top, usted puede elegir el nombre que quiera. La siguiente figura presenta una lista de enlace simple de tres nodos, donde top referencia al nodo A, A conecta con B y B conecta con C y C es el nodo final:

Un algoritmo comn de las listas de enlace simple es la insercin de nodos. Este algoritmo est implicado de alguna forma porue tiene mucho que ver con cuatro casos: cuando el nodo se debe insertar antes del primer nodo; cuando el nodo se debe insertar despus del ltimo nodo; cuando el nodo se debe insertar entre dos nodos; y cuando la lista de enlace simple no existe. Antes de estudiar cada caso consideremos el siguiente pseudocdigo:

DECLARE CLASS Node DECLARE STRING name DECLARE Node next END DECLARE DECLARE Node top = NULL

Este pseudocdigo declara una clase auto-referenciada llamada Node con un campo no de enlace llamado name y un campo de enlace llamado next. Tambin declara una variable de referencia top (del tipo Node) que contiene una referencia al primer Node de una lista de enlace simple. Como la lista todava no existe, el valor inicial de top es NULL. Cada uno de los siguientes cuatro casos asume las declaraciones de Node y top:

La lista de enlace simple no existe:: Este es el caso ms simple. Se crea un Node, se asigna su referencia a top, se inicializa su campo no de enlace, y se asigna NULL a su campo de enlace. El siguiente pseudocdigo realiza estas tareas:

top = NEW Node top.name = "A" top.next = NULL


En la siguiente imagen se puede ver la lista de enlace simple que emerge del pseudocdigo anterior:

El nodo debe insertarse antes del primer nodo:. Se crea un Node, se inicialia su campo no de enlace, se asigna la referencia de top al campo de enlace next, y se asigna la referencia del Node recien creado a top. El siguiente pseudocdigo (que asume que se ha ejecutado el pseudocdigo anterior) realiza estas tareas:

DECLARE Node temp temp = NEW Node temp.name = "B" temp.next = top top = temp
El resultado del listado anterior aparece en la siguiente imagen:

El nodo debe insertarse detrs del ltimo nodo: Se crea un Node, se inicializa su campo no de enlace, se asigna NULL al campo de enlace, se atraviesa la lista de enlace simple hasta el ltimo Node, y se asigna la referencia del Node recien creado al campo next del ltimo nodo. El siguiente pseudocdigo realiza estas tareas:

temp = NEW Node temp.name = "C" temp.next = NULL DECLARE Node temp2

temp2 = top // We assume top (and temp2) are not NULL // because of the previous pseudocode WHILE temp2.next IS NOT NULL temp2 = temp2.next END WHILE // temp2 now references the last node temp2.next = temp
La siguiente imagen revela la lista despus de la insercecin del nodo C despus del nodo A.

El nodo se debe insertar entre dos nodos: Este es el caso ms complejo. Se crea un Node, se inicializa su campo no de enlace, se atraviesa la lista hasta encontrar el Node que aparece antes del nuevo Node, se asigna el campo de enlace del Node anterior al campo de enlace del Node recien creado, y se asigna la referencia del Node recien creado al campo del enlace del Node anterior. El siguiente pseudocdigo realiza estas tareas:

temp = NEW Node temp.name = "D" temp2 = top // We assume that the newly created Node // A and that Node A exists. In the real // guarantee that any Node exists, so we // for temp2 containing NULL in both the // and after the WHILE loop completes. WHILE temp2.name IS NOT "A" temp2 = temp2.next END WHILE // temp2 now references Node A. temp.next = temp2.next temp2.next = temp

is inserted after Node world, there is no would need to check WHILE loop's header

La siguiente imagen muestra la insercin del nodo D entre los nodos A y C.

El siguiente listado presenta el equivalente Java de los ejemplos de pseudocdigo de inserccin anteriores:

// SLLInsDemo.java class SLLInsDemo { static class Node String name; Node next; } {

public static void main (String [] args) { Node top = null; // 1. The singly linked list does not exist top = new Node (); top.name = "A"; top.next = null; dump ("Case 1", top); // 2. The singly linked list exists, and the node must be inserted // before the first node Node temp; temp = new Node (); temp.name = "B"; temp.next = top; top = temp; dump ("Case 2", top); // 3. The singly linked list exists, and the node must be inserted // after the last node temp = new Node (); temp.name = "C"; temp.next = null; Node temp2; temp2 = top; while (temp2.next != null) temp2 = temp2.next; temp2.next = temp; dump ("Case 3", top);

// 4. The singly linked list exists, and the node must be inserted // between two nodes temp = new Node (); temp.name = "D"; temp2 = top; while (temp2.name.equals ("A") == false) temp2 = temp2.next; temp.next = temp2.next; temp2.next = temp; dump ("Case 4", top); } static void dump (String msg, Node topNode) { System.out.print (msg + " "); while (topNode != null) { System.out.print (topNode.name + " "); topNode = topNode.next; } System.out.println (); } }
El mtodo static void dump(String msg, Node topNode) itera sobre la lista e imprime su contenido. Cuando se ejecuta SLLInsDemo, las repetidas llamadas a este mtodo dan como resultado la siguiente salida, lo que coincide con las imagnes anteriores:

Case Case Case Case

1 2 3 4

A B A B A C B A D C
Nota:

SLLInsDemo y los ejemplos de pseudocdigo anteriores empleaban un algoritmo de bsqueda lineal orientado a listas enlazadas para encontrar un Node especfico. Indudablemente usted utilizar este otro
algoritmo en sus propios programas:

Bsqueda del ltimoNode: // Assume top references a singly linked list of at least one Node. Node temp = top // We use temp and not top. If top were used, we // couldn't access the singly linked list after // the search finished because top would refer // to the final Node. WHILE temp.next IS NOT NULL temp = temp.next END WHILE

// temp now references the last Node. Bsqueda de un Node especfico: // Assume top references a singly linked list of at least one Node. Node temp = top WHILE temp IS NOT NULL AND temp.name IS NOT "A" // Search for "A". temp = temp.next END WHILE // temp either references Node A or contains NULL if Node A not found.
Otro algoritmo comn de las listas de enlace simples es el borrado de nodos. Al contrario que la inserccin de nodos, slo hay dos casos a considerar:

Borrar el Primer Asigna el enlace del campo next del nodo referenciado por top a top:

nodo:

top = top.next; // Reference the second Node (or NULL if there is only one Node)
La siguiente imagen presenta las vistas anterior y posterior de una lista donde se ha borrado el primer nodo. en esta figura, el nodo B desaparece y el nodo A se convierte en el primer nodo.

Borrar cualquier nodo que no sea el primero: Localiza el nodo que precede al nodo a borrar y le asigna el enlace que hay en el campo next del nodo a borrar al campo next del nodo que le precede. El siguiente pseudocdigo borra el nodo D:

temp = top WHILE temp.name IS NOT "A" temp = temp.next END WHILE

// We assume that temp references Node A temp.next = temp.next.next // Node D no longer exists
La siguiente figura presenta las vistas anterior y posterior de una lista donde se ha borrado un nodo intermedio. En esa figura el nodo D desaparece.

El siguiente listado representa el equivalente Java a los pseudocdigos de borrado anteriores:

// SLLDelDemo.java class SLLDelDemo { static class Node { String name; Node next; } public static void main (String [] args) { // Build Figure 6's singly linked list (i.e., B A D C) Node top = new Node (); top.name = "C"; top.next = null; Node temp = new Node (); temp.name = "D"; temp.next = top;

top = temp; temp = new Node (); temp.name = "A"; temp.next = top; top = temp; temp = new Node (); temp.name = "B"; temp.next = top; top = temp; dump ("Initial singly-linked list", top); // 1. Delete the first node top = top.next; dump ("After first node deletion", top); // Put back B temp = new Node (); temp.name = "B"; temp.next = top; top = temp; // 2. Delete any node but the first node temp = top; while (temp.name.equals ("A") == false) temp = temp.next; temp.next = temp.next.next; dump ("After D node deletion", top); } static void dump (String msg, Node topNode) { System.out.print (msg + " "); while (topNode != null) { System.out.print (topNode.name + " "); topNode = topNode.next; } System.out.println (); } }
Cuando ejecute SLLDelDemo, observar la siguiente salida:

Initial singly linked list B A D C After first node deletion A D C After D node deletion B A C
Cuidado:

Como java inicializa los campos de referencias de un objeto a null durante la construccin del objeto, no es necesario asignar explcitamente null a un campo de enlace. No olvide estas asignaciones de null en su cdigo fuente; su ausencia reduce la claridad del cdigo. Despus de estudiar SLLDelDemo, podra preguntarse qu sucede si asigna null al nodo referenciado por top: el recolector de basura recoger toda la lista? Para responder a esta cuestin, compile y ejecute el cdigo del siguiente listado:

// GCDemo.java class GCDemo { static class Node { String name; Node next; protected void finalize () throws Throwable { System.out.println ("Finalizing " + name); super.finalize (); } } public static void main (String [] args) { // Build Figure 6's singly linked list (i.e., B A D C) Node top = new Node (); top.name = "C"; top.next = null; Node temp = new Node (); temp.name = "D"; temp.next = top; top = temp; temp = new Node (); temp.name = "A"; temp.next = top; top = temp; temp = new Node (); temp.name = "B"; temp.next = top; top = temp; dump ("Initial singly-linked list", top); top = null; temp = null; for (int i = 0; i < 100; i++) System.gc (); } static void dump (String msg, Node topNode) System.out.print (msg + " "); while (topNode != null){ {

System.out.print (topNode.name + " "); topNode = topNode.next; } System.out.println (); } } GCDemo crea la misma lista de cuatro nodos que SLLDelDemo. Despus de volcar los nodos a la salida estndar, GCDemo asigna null a top y a temp. Luego, GCDemo ejecuta System.gc (); hasta 100
veces. Qu sucede despus? Mire la salida (que he observado en mi plataforma Windows):

Initial singly-linked list B A D C Finalizing C Finalizing D Finalizing A Finalizing B


La salida revela que todos los nodos de la lista de enlace simple han sido finalizados (y recolectados). Como resultado, no tiene que preocuparse de poner a null todos los enlaces de una lista de enlace simple cuando se quiera deshacer de ella. (Podra necesitar tener que incrementar el nmero de ejecuciones de System.gc (); si su salida no incluye los mensajes de finalizacin.)

Los Algoritmos de Concatenacin e Inversin


Existen muchos algoritmos tiles para listas de enlace simple. Uno de ellos es la concatenacin, que implica que puede aadir una lista de enlace simple al final de otra lista. Otro algoritmo til es la inversin. Este algoritmo invierte los enlaces de una lista de enlace simple permitiendo atravesar los nodos en direccion opuesta. El siguiente cdigo extiende la clase anterior para invertir los enlaces de la lista referenciada por top1:

> // CIDemojava class CIDemo { static class DictEntry { String word; String meaning; DictEntry next; } // ListInfo is necessary because buildList() must return two pieces // of information static class ListInfo { DictEntry top; DictEntry last; } public static void main (String [] args) { String [] wordsMaster = { "aardvark", "anxious", "asterism" }; ListInfo liMaster = new ListInfo ();

buildList (liMaster, wordsMaster); dump ("Master list =", liMaster.top); String [] wordsWorking = { "carbuncle", "catfish", "color" }; ListInfo liWorking = new ListInfo (); buildList (liWorking, wordsWorking); dump ("Working list =", liWorking.top); // Perform the concatenation liMaster.last.next = liWorking.top; dump ("New master list =", liMaster.top); invert (liMaster); dump ("Inverted new master list =", liMaster.top); } static void buildList (ListInfo li, String [] words) { if (words.length == 0) return; // Create a node for first word/meaning li.top = new DictEntry (); li.top.word = words [0]; li.top.meaning = null; // Initialize last reference variable to // simplify append and make concatenation possible. li.last = li.top; for (int i = 1; i < words.length; i++) { // Create (and append) a new node for next word/meaning li.last.next = new DictEntry (); li.last.next.word = words [i]; li.last.next.meaning = null; // Advance last reference variable to simplify // append and make concatenation possible li.last = li.last.next; } li.last.next = null; } static void dump (String msg, DictEntry topEntry) { System.out.print (msg + " "); while (topEntry != null) { System.out.print (topEntry.word + " "); topEntry = topEntry.next;

} System.out.println (); } static void invert (ListInfo li) { DictEntry p = li.top, q = null, r; while (p != null) r = q; q = p; p = p.next; q.next = r; } li.top = q; } } CIDemo declara un DictEntry anidado en la clase de ms alto nivel cuyos objetos contienen palabras y
significados. (Para mentener el programa lo ms sencillo posible, he evitado los significados. Usted puede aadirlos si lo desea). CIDemo tambin declara ListInfo para seguir las referencias el primero y ltimo DictEntry de una lista de enlace simple. El thread principal ejecuta el mtodo public static void main(String [] args) de CIDemo. Este thread llama dos veces al mtodo static void buildList (ListInfo li, String [] words) para crear dos listas de enlace simple: una lista maestra (cuyos nodos se rellenan con palabras del array wordsMaster), y una lista de trabajo (cuyos nodos se rellenan con palabras del array wordsWorking). Antes de cada llamada al mtodo buildList (ListInfo li, String [] words), el thread principal crea y pasa un objeto ListInfo. este objeto devuelve las referencias al primero y ltimo nodo. (Una llamada a mtodo devuelve directamente un slo dato). Despus de construir una lista de enlace simple, el thread principal llama a static void dump (String msg, DictEntry topEntry) para volcar un mensaje y las palabras de los nodos de una lista en el dispositivo de salida estndar. Se podra estar preguntando sobre la necesidad del campo last de ListInfo. Este campo sirve a un doble propsito: primero, simplifica la creacin de cada lista, donde se aaden los nodos. Segundo, este campo simplifica la concatenacin, que se queda slo en la ejecucin de la siguiente lnea de cdigo: liMaster.last.next = liWorking.top;. Una vez que se completa la concatenacin, y el thread principal vuelva los resultados de la lista maestra en la salida estndar, el thread llama al mtodo static void invert (ListInfo li) para invertir la lista maestra y luego muestra la lista maestra invertida por la salida estndar. Cuando ejecute CIDemo ver la siguiente salida:

Master list = aardvark anxious asterism Working list = carbuncle catfish color New master list = aardvark anxious asterism carbuncle catfish color Inverted new master list = color catfish carbuncle asterism anxious aardvark

Lista Doblemente Enlazada


Las listas de enlace simple restringen el movimiento por lo nodos a una sla direccin: no puede atravesar una lista de enlace simple en direccin opuesta a menos que primero utilice el algoritmo de inversin para invertir

los enlaces de los nodos, lo que lleva tiempo. Despus de atraversarlos en direccin opuesta, problamente necesitar repetir la inversin para restaurar el orden original, lo que lleva an ms tiempo. Un segundo problema implica el borrado de nodos: no puede borrar un nodo arbitrario sin acceder al predecesor del nodo. Estos problemas desaperecen cuando se utiliza una lista doblemente enlazada. Una lista doblemente enlazada es una lista enlazada de nodos, donde cada nodo tiene un par de campos de enlace. Un campo de enlace permite atravesar la lista hacia adelante, mientras que el otro permite atravesar la lista haca atrs. Para la direccin hacia adelante, una variable de referencia contiene una referencia al primer nodo. Cada nodo se enlaza con el siguiente mediante el campo de enlace next, excepto el ltimo nodo, cuyo campo de enlace next contiene null para indicar el final de la lista (en direccion hacia adelante). De forma similar, para la direccin contraria, una variable de referencia contiene una referencia al ltimo nodo de la direccin normal (hacia adelante), lo que se interpreta como el primer nodo. Cada nodo se enlaza con el anterior mediante el campo de enlace previous, y el primer nodo de la direccion hacia adelante, contiene null en su campo previous para indicar el fin de la lista. La siguiente figura representa una lista doblemente enlazada de tres nodos, donde topForward referencia el primer nodo en la direccion hacia adelante, y topBackward referencia el primero nodo la direccin inversa.

Truco: Piense en una lista doblemente enlazada como una pareja de listas de enlace simple que interconectan los mismos nodos. La insercin y borrado de nodos en una lista doblemente enlazada son operaciones comunes. Estas operaciones se realizan mediante algoritmos que se basan en los algoritmos de insercin y borrado de las listas de enlace simple (porque las listas doblemente enlazadas slo son una pareja de listas de enlace simple que interconectan los mismos nodos).

El siguiente listado muestra la insercin de nodos para crear la lista de la figura anterior, el borrado de nodos ya que elimina el nodo B de la lista, y el movimiento por la lista en ambas direcciones:

// DLLDemo.java class DLLDemo { static class Node { String name; Node next; Node prev; } public static void main (String [] args) { // Build a doubly linked list Node topForward = new Node (); topForward.name = "A"; Node temp = new Node (); temp.name = "B"; Node topBackward = new Node (); topBackward.name = "C"; topForward.next = temp; temp.next = topBackward; topBackward.next = null; topBackward.prev = temp; temp.prev = topForward; topForward.prev = null; // Dump forward singly linked list System.out.print ("Forward singly-linked list: "); temp = topForward; while (temp != null){ System.out.print (temp.name); temp = temp.next; } System.out.println (); // Dump backward singly linked list System.out.print ("Backward singly-linked list: "); temp = topBackward; while (temp != null){ System.out.print (temp.name); temp = temp.prev; } System.out.println (); // Reference node B

temp = topForward.next; // Delete node B temp.prev.next = temp.next; temp.next.prev = temp.prev; // Dump forward singly linked list System.out.print ("Forward singly-linked list (after deletion): "); temp = topForward; while (temp != null){ System.out.print (temp.name); temp = temp.next; } System.out.println (); // Dump backward singly linked list System.out.print "); temp = topBackward; while (temp != null){ System.out.print (temp.name); temp = temp.prev; } System.out.println (); } }
Cuando se ejecuta, DLLDemo produce la siguiente salida:

("Backward

singly-linked

list

(after

deletion):

Forward singly-linked list: ABC Backward singly-linked list: CBA Forward singly-linked list (after deletion): AC Backward singly-linked list (after deletion): CA

Algoritmo de Insercin-Ordenada
Algunas veces querr crear una lista doblemente enlazada que organice el orden de sus nodos basndose en un campo no de enlace. Atravesar la lista doblemente enlazada en una direccin presenta esos nodos en orden ascendente, y atravsarla en en direccin contraria los presenta ordenados descedentemente. El algoritmo de ordenacin de burbuja es inapropiado en este caso porque requiere ndices de array. Por el contrario, insercin-ordenada construye una lista de enlace simple o una lista doblemente enlzada ordenadas por un campo no de enlace para identificar el punto de insercin de cada nuevo nodo. El siguiente litado demuestra el algoritmo de insercin-ordenada:

// InsSortDemo.java class InsSortDemo {

// Note: To keep Employee simple, I've omitted various constructor and // nonconstructor methods. In practice, such methods would be present. static class Employee { int empno; String name; Employee next; Employee prev; } public static void main (String [] args) { // Data for a doubly linked list of Employee objects. The lengths of // the empnos and names arrays must agree. int [] empnos = { 687, 325, 567, 100, 987, 654, 234 }; String [] names = { "April", "Joan", "Jack", "George", "Brian", "Sam", "Alice" }; Employee topForward = null; Employee topBackward = null; // Prime the doubly linked list by creating the first node. topForward = new Employee (); topForward.empno = empnos [0]; topForward.name = names [0]; topForward.next = null; topForward.prev = null; topBackward = topForward; // empno) // into the doubly linked list. for (int i = 1; i < empnos.length; i++) { // Create and initialize a new Employee node. Employee e = new Employee (); e.empno = empnos [i]; e.name = names [i]; e.next = null; e.prev = null; // Locate the first Employee node whose empno is greater than // the empno of the Employee node to be inserted. Employee temp = topForward; while (temp != null && temp.empno <= e.empno) temp = temp.next; // temp is either null (meaning that the Employee node must be // appended) or not null (meaning that the Employee node must // be inserted prior to the temp-referenced Employee node). if (temp == null) { Insert remaining Employee nodes (in ascending order -via

topBackward.next = e; // Append new Employee node to // forward singly linked list. e.prev = topBackward; // Update backward singly linked topBackward = e; // list as well. } else{ if (temp.prev == null) { e.next = topForward; // Insert new Employee node at topForward = e; // head of forward singly linked // list. temp.prev = e; // Update backward singly linked // list as well. } else { e.next = temp.prev.next; // Insert new Employee node temp.prev.next = e; // after last Employee node // whose empno is smaller in // forward singly linked list. e.prev = temp.prev; // Update backward temp.prev = e; //singly linked list as well. } } } // Dump forward singly linked list (ascending order). System.out.println ("Ascending order:\n"); Employee temp = topForward; while (temp != null) { System.out.println ("[" + temp.empno + ", " + temp.name + "] "); temp = temp.next; } System.out.println (); // Dump backward singly linked list (descending order). System.out.println ("Descending order:\n"); temp = topBackward; while (temp != null) { System.out.println ("[" + temp.empno + ", " + temp.name + "] "); temp = temp.prev; } System.out.println (); } } InsSortDemo simplifica su operacin creando primero un nodo Employee primario. Para el resto de nodos Employee, InsSortDemo localiza la posicin de insercin apropiada basndose en el campo no de enlace empno, y luego inserta el Employee en esa posicin. Cuando ejecute InsSortDemo, podr
observar la siguiente salida:

Ascending order: [100, [234, [325, [567, [654, [687, [987, George] Alice] Joan] Jack] Sam] April] Brian]

Descending order: [987, [687, [654, [567, [325, [234, [100, Brian] April] Sam] Jack] Joan] Alice] George]

Tanto la insercin-ordenada como la ordenacin de burbuja exhiben prcticamente el mismo rendimiento.

Lista de Enlace Circular


El campo de enlace del ltimo nodo de una lista de enlace simple contiene un enlace nulo, ocurre lo mismo en los campos de enlace del primer y ltimo elemento en ambas direcciones en las listas doblemente enlazadas. Supongamos que en vez de esto los ltimos nodos contiene un enlace a los primeros nodos. En esta situacion, usted terminar con una lista de enlace circular, como se ve en la siguiente figura:

Las listas de enlace circular se utilizan con frecuencia en procesamiento repetitivo de nodos en un orden especfico. Dichos nodos podran representar conexiones de servidor, procesadores esperando una seccin crtica, etc. Esta estructura de datos tambin sirve como base para una variante de una estructura de datos ms compleja: la cola (que veremos ms adeltante).

Listas Enlazadas frente a Arrays


Las listas enlazadas tienen las siguiente ventajas sobre los arrays:

No requieren memoria extra para soportar la expansin. Por el contrario, los arrays requieren memoria extra si se necesita expandirlo (una vez que todos los elementos tienen datos no se pueden aadir datos nuevos a un array). Ofrecen una insercin/borrado de elementos ms rpida que sus operaciones equivalentes en los arrays. Slo se tienen que actualizar los enlaces despus de identificar la posicin de

insercin/borrado. Desde la perspectiva de los arrays, la insercin de datos requiere el movimiento de todos los otros datos del array para crear un elemento vaco. De forma similar, el borrado de un dato existente requiere el movimiento de todos los otros datos para eliminar el elementovaco. En contraste, los arrays ofrecen las siguiente ventajas sobre las listas enlazadas:

Los elementos de los arrays ocupan menos memoria que los nodos porque no requieren campos de enlace. Los arrays ofrecen un aceso ms rpido a los datos, medante ndices basados en enteros.

Las listas enlazadas son ms apropiadas cuando se trabaja con datos dinmicos. En otras palabras, inserciones y borrados con frecuencia. Por el contrario, los arrays son ms apropiados cuando los datos son estticos (las inserciones y borrados son raras). De todas formas, no olvide que si se queda sin espacio cuando aade tems a un array, debe crear un array ms grande, copiar los datos del array original el nuevo array mayor y elimiar el original. Esto cuesta tiempo, lo que afecta especialmente al rendimiento si se hace repetidamente. Mezclando una lista de enlace simple con un array uni-dimensional para acceder a los nodos mediante los ndices del array no se consigue nada. Gastar ms memoria, porque necesitar los elementos del array ms los nodos, y tiempo, porque necesitar mover los tems del array siempre que inserte o borre un nodo. Sin embargo, si es posible integrar el array con una lista enlazada para crear una estructura de datos til (por ejemplo, las tablas hash).

Publicado por: Alberto de la Torre Recomendar a un amigo Compartir en redes

Comentarios

Pilas y colas

Inicio Noticias Articulos Cdigo Foros Enlaces Hosting Anuncios

Categoras destacadas

Artculo
InicioArtculoLenguajes orientados a objetoJavaJ2EE

votar!

20 Estructuras de Datos y Algoritmos en Java

Pilas y Colas o Pilas que "Recuerdan" o Priorizar con Colas

Pilas y Colas
Los desarrolladores utilizan los arrays y las variantes de listas enlazadas para construir una gran variedad de estructuras de datos complejas. Este pgina explora dos de esas estructuras: las Pilas, las Colas . Cuando presentemos los algoritmos lo haremos ncamente en cdigo Java por motivos de brevedad.

Pilas que "Recuerdan"


La Pila es una estrucutra de datos donde las inserciones y recuperaciones/borrados de datos se hacen en uno de los finales, que es conocido como el top de la pila. Como el ltimo elemento insertado es el primero en recuperarse/borrarse, los desarrolladores se refieren a estas pilas como pilas LIFO (last-in, first-out). Los datos se push (insertan) dentro y se pop (recuperan/borran) de la parte superior de la pila. La siguiente figura ilustra una pila con tres String cada uno insertado en la parte superior de la pila:

Como muestra la figura anterior, las pilas se construyen en memoria. Por cada dato insertado, el itm superior anterior y todos los datos inferiores se mueven hacia abajo. Cuando llega el momento de sacar un tem de la pila, se recpupera y se borra de la pila el tem superior (que en la figura anterior se revela como "third"). Las pilas son muy tiles en varios escenarios de programacin. Dos de los ms comunes son:

Pilas que contienen direcciones de retorno: Cuando el cdigo llama a un mtodo, la direccin de la primera instruccin que sigue a la llamada se inserta en la parte superior de la pila de llamadas de mtodos del thread actual. Cuando el mtodo llamado ejecuta la instruccin return, se saca la direccin de la parte superior de la pila y la ejecucin contina en sa direccin. Si un mtodo llama a otro mtodo, el comportamiento LIFO de la pila asegura que la instruccin return del segundo mtodo

transfiere la ejecucin al primer mtodo, y la del primer mtodo transfiere la ejecucin al cdigo que sigue al cdigo que llam al primer mtodo. Como resultado una pila "recuerda" las direcciones de retorno de los mtodos llamados. Pilas que contienen todos los parmetros del mtodo llamado y las variables locales: Cuando se llama a un mtodo, la JVM reserva memoria cerca de la direccin de retorno y almacena todos los parmetros del mtodo llamado y las variables locales de ese mtodo. Si el mtodo es un mtodo de ejemplar, uno de los parmetros que almacena en la pila es la referencia this del objeto actual.

Es muy comn implementar una pila utilizando un array uni-dimensional o una lista de enlace simple. En el escenario del array uni-dimensional, una variable entera, tpicamente llamada top, contiene el ndice de la parte superior de la pila. De forma similar, una variable de referencia, tambin nombrada noramlmente como top, referencia el nodo superior del escenario de la lista de enlace simple. He modelado mis implementaciones de pilas despus de encontrar la arquitectura del API Collections de Java. Mis implementaciones constan de un interface Stack para una mxima flexibilidad, las clases de implementacin ArrayStack y LinkedListStack, y una clase de soporte FullStackException. Para facilitar su distribucin, he empaquetado estas clases en un paquete llamado com.javajeff.cds, donde cds viene de estructura de datos complejas. El siguiente listado presenta el interface Stack:

// Stack.java package com.javajeff.cds; public interface Stack { boolean isEmpty (); Object peek (); void push (Object o); Object pop (); }
Sus cuatro mtodos determinan si la pila est vaca, recuperan el elemento superior sin borrarlo de la pia, situan un elemento en la parte superior de la pila y el ltimo recuera/borra el elemento superior. Aparte de un constructor especfico de la implementacin, su programa nicamente necesita llamar a estos mtodos. El siguiente listado presenta una implementacin de un Stack basado en un array uni-dimensional:

// ArrayStack.java package com.javajeff.cds; public class ArrayStack implements Stack private int top = -1; private Object [] stack; {

public ArrayStack (int maxElements) { stack = new Object [maxElements]; } public boolean isEmpty () { return top == -1; } public Object peek () { if (top < 0)

throw new java.util.EmptyStackException (); return stack [top]; } public void push (Object o) { if (top == stack.length - 1) throw new FullStackException (); stack [++top] = o; } public Object pop () { if (top < 0) throw new java.util.EmptyStackException (); return stack [top--]; } } ArrayStack revela una pila como una combinacin de un ndice entero privado top y variables de referencia de un array uni-dimensional stack. top identifica el elemento superior de la pila y lo inicializa a 1 para indica que la pila est vaca. Cuando se crea un objeto ArrayStack llama a public ArrayStack(int maxElements) con un valor entero que representa el nmero mximo de elementos. Cualquier intento de sacar un elemento de una pila vaca mediante pop() resulta en el lanzamiento de una java.util.EmptyStackException. De forma similar, cualquier intento de poner ms elementos de maxElements dentro de la pila utilizando push(Object o) lanzar una FullStackException,
cuyo cdigo aparece en el siguiente listado:

// FullStackException.java package com.javajeff.cds; public class FullStackException extends RuntimeException { }


Por simetra con EmptyStackException, FullStackException extiende RuntimeException. Como resultado no se necesita aadir FullStackException a la clausula throws del mtodo. El siguiente listado presenta una implementacin de Stack utilizando una lista de enlace simple:

// LinkedListStack.java package com.javajeff.cds; public class LinkedListStack implements Stack private static class Node { Object o; Node next; } private Node top = null; public boolean isEmpty () { return top == null; } public Object peek () { {

if (top == null) throw new java.util.EmptyStackException (); return top.o; } public void push (Object o) { Node temp = new Node (); temp.o = o; temp.next = top; top = temp; } public Object pop () { if (top == null) throw new java.util.EmptyStackException (); Object o = top.o; top = top.next; return o; } } LinkedListStack revela una pila como una combinacin de una clase anidada privada de alto nivel llamada Node y una variable de referencia privada top que se inicialia a null para indicar una pila vaca. Al contrario que su contrapartida del array uni-dimensional, LinkedListStack no necesita un constructor ya que se expande dinmicamente cuando se ponen los tems en la pila. As, void push(Object o) no necesita lanzar una FullStackException. Sin embargo, Object pop() si debe chequear si la pila est vaca, lo que podra resultar en el lanzamiento de una EmptyStackException.
Ahora que ya hemos visto el interface y las tres clases que generan mis implementaciones de las pilas, juguemos un poco. El siguiente listado muestra casi todo el soporte de pilas de mi paquete com.javajeff.cds:

// StackDemo.java import com.javajeff.cds.*; class StackDemo { public static void main (String [] args) { System.out.println ("ArrayStack Demo"); System.out.println ("---------------"); stackDemo (new ArrayStack (5)); System.out.println ("LinkedListStack Demo"); System.out.println ("--------------------"); stackDemo (new LinkedListStack ()); } static void stackDemo (Stack s) { System.out.println ("Pushing \"Hello\""); s.push ("Hello"); System.out.println ("Pushing \"World\""); s.push ("World"); System.out.println ("Pushing StackDemo object"); s.push (new StackDemo ());

System.out.println ("Pushing Character object"); s.push (new Character ('C')); System.out.println ("Pushing Thread object"); s.push (new Thread ("A")); try { System.out.println ("Pushing \"One last item\""); s.push ("One last item"); } catch (FullStackException e) { System.out.println ("One push too many"); } System.out.println (); while (!s.isEmpty ()) System.out.println (s.pop ()); try { s.pop (); } catch (java.util.EmptyStackException e) { System.out.println ("One pop too many"); } System.out.println (); } }
Cuando se ejecuta StackDemo, produce la siguiente salida:

ArrayStack Demo --------------Pushing "Hello" Pushing "World" Pushing StackDemo object Pushing Character object Pushing Thread object Pushing "One last item" One push too many Thread[A,5,main] C StackDemo@7182c1 World Hello One pop too many LinkedListStack Demo -------------------Pushing "Hello" Pushing "World" Pushing StackDemo object Pushing Character object Pushing Thread object Pushing "One last item"

One last item Thread[A,5,main] C StackDemo@cac268 World Hello One pop too many

Priorizar con Colas


La Cola es una estructura de datos donde la insercin de tem se hace en un final (el fin de la cola) y la recuperacin/borrado de elementos se hace en el otro final (el inicio de la cola). Como el primer elemento insertado es el primero en ser recuperado, los desarrolladores se refieren a estas colas como estructuras FIFO (first-in, first-out). Normalmente los desarrolladores tabajan con dos tipos de colas: lineal y circular. En ambas colas, la insercin de datos se realiza en el fin de la cola, se mueven hacia adelante y se recuperan/borran del incio de la cola. La siguiente figura ilustra las colas lineal y circular:

La cola lineal de la figura anterior almacena cuatro enteros, con el entero 1 en primer lugar. Esa cola est llena y no puede almacenar ms datos adicionales porque rear identifica la parte final de la cola. La razn de la posicin vaca, que identifica front, implica el comportamiento lineal de la cola. Inicialmente, front y rear identifican la posicin ms a la izquierda, lo que indica que la cola est vaca. Para almacenar el entero 1, rear avanza una posicin hacia la derecha y almacena 1 en esa posicin. Para recuperar/borrar el entero 1, front avanza una posicin hacia la derecha. Nota:

Para sealar que la cola lineal est vaca, no necesita gastar una posicin, aunque esta aproximacin algunas veces es muy conneniente. En su lugar asigne el mismo valor que indique una posicin no existente a front y a rear. Por ejemplo, asumiendo una implementacin basada en un array uni-dimensional, front y rear podran contener -1. El ndice 0 indica entonces la posicin ms a la izquierda, y los datos se insertarn empezando en este ndice. Cuando rear identifique la posicin ms a la derecha, la cola lineal podra no estar llena porque front podra haber avanzado almenos una posicin para recuperar/borrar un dato. En este esceario, considere mover todos los tems de datos hacia la izquierda y ajuste la posicin de front y rear de la forma apropiada para crear ms espacio. Sin embargo, demasiado movimiento de datos puede afectar al rendimiento, por eso debe pensar cuidadosamente en los costes de rendimiento si necesita crear ms espacio. La cola circular de la figura anterior tiene siete datos enteros, con el entero 1 primero. Esta cola est llena y no puede almacenar ms datos hasta que front avance una posicin en sentido horario (para recuperar el entero 1) y rear avance una posicin en la misma direcin (para identificar la posicin que contendr el nuevo entero). Al igual que con la cola lineal, la razon de la posicin vaca, que identifica front, implica el comportamiento circular de la cola. Inicialmente, front y rear identifican la misma posicin, lo que indica una cola vaca. Entonces rear avanza una posicin por cada nueva insercin. De forma similar, front avanza una posicin por cada recuperacin/borrado. Las colas son muy tiles en varios escenarios de programacin, entre los que se encuentran:

Temporizacin de Threads: Una JVM o un sistema operativo subyacente podran establecer varias colas para coincidir con diferentes prioridades de los threads. La informacin del thread se bloquea porque todos los threads con una prioridad dada se almacenan en una cola asociada. Trabajos de impresin: Como una impresora normalmente es ms lenta que un ordenador, un sistema operativo maneja los trabajos de impresin en un subsistema de impresin, que inserta esos trabajos de impresin en una cola. El primer trabajo en esa cola se imprime primero, y as sucesivamente.

Los desarrolladores normalmente utilizan una array uni-dimensional para implementar una cola. Sin embargo, si tienen que co-existir mltiple colas o las inserciones en las colas deben ocurrir en posiciones distintas a la ltima por motivos de prioridades, los desarrolladores suelen cambiar a la lista doblemente enlazada. Con un array uni-dimensional dos variables enteras (normalmente llamadas front y rear) contienen los ndices del primer y ltimo elemento de la cola, respectivamente. Mis implementaciones de colas lineales y circulares usan un array uni-dimensional y empiezan con el interface Queue que puede ver en el siguiente listado:

// Queue.java package com.javajeff.cds; public interface Queue { void insert (Object o); boolean isEmpty (); boolean isFull (); Object remove (); } Queue declara cuatro mtodos para almacenar un datos, determinar si la cola est vaca, determinar si la cola
est llena y recuperar/borrar un dato de la cola. Llame a estos mtodos (y a un constructor) para trabajar con cualquier implementacin de Queue.

El siguiente listado presenta una a implementacin de Queue de una cola lineal basada en un array unidimensional:

// ArrayLinearQueue.java package com.javajeff.cds; public class ArrayLinearQueue implements Queue { private int front = -1, rear = -1; private Object [] queue; public ArrayLinearQueue (int maxElements) { queue = new Object [maxElements]; } public void insert (Object o) { if (rear == queue.length - 1) throw new FullQueueException (); queue [++rear] = o; } public boolean isEmpty () { return front == rear; } public boolean isFull () { return rear == queue.length - 1; } public Object remove () { if (front == rear) throw new EmptyQueueException (); return queue [++front]; } } ArrayLinearQueue revela que una cola es una combinacin de variables privadas front, rear, y queue. front y rear se inicializan a -1 para indicar una cola vaca. Igual que el constructor de ArrayStack llama a public ArrayLinearQueue(int maxElements) con un valor entero que especifique el nmero mximo de elementos durante la construccin de un objeto ArrayLinearQueue.
El mtodo insert(Object o) de ArrayLinearQueue lanza una FullQueueException cuando rear identifica el elemento final del array uni-dimensional. El cdigo de FullQueueException aparece en el siguiente listado:

// FullQueueException.java package com.javajeff.cds; public class FullQueueException extends RuntimeException { }


El mtodo remove() de ArrayLinearQueue lanza una EmptyQueueException cuando los objetos front y rear son iguales. El siguiente listado presenta el cdigo de esta clase:

// EmptyQueueException.java package com.javajeff.cds; public class EmptyQueueException extends RuntimeException { }


El siguiente listado presenta una implementacin de Queue para una cola circular basada en un array unidimensional:

// ArrayCircularQueue.java package com.javajeff.cds; public class ArrayCircularQueue implements Queue { private int front = 0, rear = 0; private Object [] queue; public ArrayCircularQueue (int maxElements) { queue = new Object [maxElements]; } public void insert (Object o) { int temp = rear; rear = (rear + 1) % queue.length; if (front == rear) { rear = temp; throw new FullQueueException (); } queue [rear] = o; } public boolean isEmpty () { return front == rear; } public boolean isFull () { return ((rear + 1) % queue.length) == front; } public Object remove () { if (front == rear) throw new EmptyQueueException (); front = (front + 1) % queue.length; return queue [front]; } } ArrayCircularQueue revela una implementacin, en terminos de variables privadas y un constructor, muy similar a ArrayLinearQueue. El mtodo insert(Object o) es interesante porque guarda el valor actual de rear antes de hacer que esa variable apunte a la siguiente posicin. Si la cola circular est llena, rear restaura su valor original antes de lanzar una FullQueueException. La restauracin de rear es necesaria porque front es igual a rear (en ese punto), y una subsecuente llamada a remove() resulta en la lanzamiento de una EmptyQueueException (incluso aunque la cola circular no est vaca).

Despus de estudiar el cdigo del interface y de varias clases que lo implementan basndose en arrays unidimensionales, consideremos en el siguiente listado una aplicacin que demuestra las colas lineales y circulares:

// QueueDemo.java import com.javajeff.cds.*; class QueueDemo { public static void main (String [] args) { System.out.println ("ArrayLinearQueue Demo"); System.out.println ("---------------------"); queueDemo (new ArrayLinearQueue (5)); System.out.println ("ArrayCircularQueue Demo"); System.out.println ("---------------------"); queueDemo (new ArrayCircularQueue (6)); // Need one more slot because // of empty slot in circular // implementation } static void queueDemo (Queue q) { System.out.println ("Is empty = " + q.isEmpty ()); System.out.println ("Is full = " + q.isFull ()); System.out.println ("Inserting \"This\""); q.insert ("This"); System.out.println ("Inserting \"is\""); q.insert ("is"); System.out.println ("Inserting \"a\""); q.insert ("a"); System.out.println ("Inserting \"sentence\""); q.insert ("sentence"); System.out.println ("Inserting \".\""); q.insert ("."); try { System.out.println ("Inserting \"One last item\""); q.insert ("One last item"); } catch (FullQueueException e) { System.out.println ("One insert too many"); System.out.println ("Is empty = " + q.isEmpty ()); System.out.println ("Is full = " + q.isFull ()); } System.out.println (); while (!q.isEmpty ()) System.out.println (q.remove () + " [Is q.isEmpty () + ", Is full = " + q.isFull () + "]"); empty = " +

try { q.remove (); } catch (EmptyQueueException e) { System.out.println ("One remove too many"); } System.out.println (); } }
Cuando se ejecuta QueueDemo, se produce la siguiente salida:

ArrayLinearQueue Demo --------------------Is empty = true Is full = false Inserting "This" Inserting "is" Inserting "a" Inserting "sentence" Inserting "." Inserting "One last item" One insert too many Is empty = false Is full = true This [Is empty = false, Is full = true] is [Is empty = false, Is full = true] a [Is empty = false, Is full = true] sentence [Is empty = false, Is full = true] . [Is empty = true, Is full = true] One remove too many ArrayCircularQueue Demo --------------------Is empty = true Is full = false Inserting "This" Inserting "is" Inserting "a" Inserting "sentence" Inserting "." Inserting "One last item" One insert too many Is empty = false Is full = true This [Is empty = false, Is full = false] is [Is empty = false, Is full = false] a [Is empty = false, Is full = false] sentence [Is empty = false, Is full = false] . [Is empty = true, Is full = false] One remove too many

Publicado por: Alberto de la Torre Recomendar a un amigo Compartir en redes

Comentarios
Buscar...

BBDD Entornos de desarrollo Entretenimiento Herramientas Internet Lenguajes de script Lenguajes imperativos Lenguajes orientados a objeto Otros lenguajes Plataformas Teora Varios

ltimas noticias
IBM Global Entrepreneur Program: una solucin para poner en marcha tu start up SEO Administrator Presentacin de Play framework 2.0 Anuncio de Play! framework 2.0 en espaol
Ver ms

ltimos artculos
Entity Framework Code First (4) Entity Framework Code First (3) Entity Framework Code First (2) Entity Framework Code First (1)
Ver ms

ltimos cdigos
MessageBox sencillo con JQuery UI Mascara para Text (SWT) Convierte cursor de lectura en cursor de escritura Tres en Raya o Juego del Gato
Ver ms

Copyright 1998-2011 Programacin en Castellano. Todos los derechos reservados Datos legales | Politica de privacidad | Contacte con nosotros | Publicidad Diseo web y desarrollo web. Un proyecto de los hermanos Carrero. Red internet: Juegos gratis | Servidores dedicados Ms internet: Password | Directorio de weblogs | Favicon <p><img alt="Clicky" width="1" height="1" src="http://in.getclicky.com/208180ns.gif" /></p>

Inicio Noticias Articulos Cdigo Foros Enlaces Hosting Anuncios

Categoras destacadas

Artculo
InicioArtculoLenguajes orientados a objetoJavaJ2EE

votar!

20 Estructuras de Datos y Algoritmos en Java

Pilas y Colas o Pilas que "Recuerdan" o Priorizar con Colas

Pilas y Colas
Los desarrolladores utilizan los arrays y las variantes de listas enlazadas para construir una gran variedad de estructuras de datos complejas. Este pgina explora dos de esas estructuras: las Pilas, las Colas . Cuando presentemos los algoritmos lo haremos ncamente en cdigo Java por motivos de brevedad.

Pilas que "Recuerdan"


La Pila es una estrucutra de datos donde las inserciones y recuperaciones/borrados de datos se hacen en uno de los finales, que es conocido como el top de la pila. Como el ltimo elemento insertado es el primero en recuperarse/borrarse, los desarrolladores se refieren a estas pilas como pilas LIFO ( last-in, first-out). Los datos se push (insertan) dentro y se pop (recuperan/borran) de la parte superior de la pila. La siguiente figura ilustra una pila con tres String cada uno insertado en la parte superior de la pila:

Como muestra la figura anterior, las pilas se construyen en memoria. Por cada dato insertado, el itm superior anterior y todos los datos inferiores se mueven hacia abajo. Cuando llega el momento de sacar un tem de la pila, se recpupera y se borra de la pila el tem superior (que en la figura anterior se revela como "third"). Las pilas son muy tiles en varios escenarios de programacin. Dos de los ms comunes son:

Pilas que contienen direcciones de retorno: Cuando el cdigo llama a un mtodo, la direccin de la primera instruccin que sigue a la llamada se inserta en la parte superior de la pila de llamadas de mtodos del thread actual. Cuando el mtodo llamado ejecuta la instruccin return, se saca la direccin de la parte superior de la pila y la ejecucin contina en sa direccin. Si un mtodo llama a otro mtodo, el comportamiento LIFO de la pila asegura que la instruccin return del segundo mtodo transfiere la ejecucin al primer mtodo, y la del primer mtodo transfiere la ejecucin al cdigo que sigue al cdigo que llam al primer mtodo. Como resultado una pila "recuerda" las direcciones de retorno de los mtodos llamados. Pilas que contienen todos los parmetros del mtodo llamado y las variables locales: Cuando se llama a un mtodo, la JVM reserva memoria cerca de la direccin de retorno y almacena todos los parmetros del mtodo llamado y las variables locales de ese mtodo. Si el mtodo es un mtodo de ejemplar, uno de los parmetros que almacena en la pila es la referencia this del objeto actual.

Es muy comn implementar una pila utilizando un array uni-dimensional o una lista de enlace simple. En el escenario del array uni-dimensional, una variable entera, tpicamente llamada top, contiene el ndice de la

parte superior de la pila. De forma similar, una variable de referencia, tambin nombrada noramlmente como top, referencia el nodo superior del escenario de la lista de enlace simple. He modelado mis implementaciones de pilas despus de encontrar la arquitectura del API Collections de Java. Mis implementaciones constan de un interface Stack para una mxima flexibilidad, las clases de implementacin ArrayStack y LinkedListStack, y una clase de soporte FullStackException. Para facilitar su distribucin, he empaquetado estas clases en un paquete llamado com.javajeff.cds, donde cds viene de estructura de datos complejas. El siguiente listado presenta el interface Stack:

// Stack.java package com.javajeff.cds; public interface Stack { boolean isEmpty (); Object peek (); void push (Object o); Object pop (); }
Sus cuatro mtodos determinan si la pila est vaca, recuperan el elemento superior sin borrarlo de la pia, situan un elemento en la parte superior de la pila y el ltimo recuera/borra el elemento superior. Aparte de un constructor especfico de la implementacin, su programa nicamente necesita llamar a estos mtodos. El siguiente listado presenta una implementacin de un Stack basado en un array uni-dimensional:

// ArrayStack.java package com.javajeff.cds; public class ArrayStack implements Stack private int top = -1; private Object [] stack; {

public ArrayStack (int maxElements) { stack = new Object [maxElements]; } public boolean isEmpty () { return top == -1; } public Object peek () { if (top < 0) throw new java.util.EmptyStackException (); return stack [top]; } public void push (Object o) { if (top == stack.length - 1) throw new FullStackException (); stack [++top] = o; } public Object pop () { if (top < 0)

throw new java.util.EmptyStackException (); return stack [top--]; } } ArrayStack revela una pila como una combinacin de un ndice entero privado top y variables de referencia de un array uni-dimensional stack. top identifica el elemento superior de la pila y lo inicializa a 1 para indica que la pila est vaca. Cuando se crea un objeto ArrayStack llama a public ArrayStack(int maxElements) con un valor entero que representa el nmero mximo de elementos. Cualquier intento de sacar un elemento de una pila vaca mediante pop() resulta en el lanzamiento de una java.util.EmptyStackException. De forma similar, cualquier intento de poner ms elementos de maxElements dentro de la pila utilizando push(Object o) lanzar una FullStackException,
cuyo cdigo aparece en el siguiente listado:

// FullStackException.java package com.javajeff.cds; public class FullStackException extends RuntimeException { }


Por simetra con EmptyStackException, FullStackException extiende RuntimeException. Como resultado no se necesita aadir FullStackException a la clausula throws del mtodo. El siguiente listado presenta una implementacin de Stack utilizando una lista de enlace simple:

// LinkedListStack.java package com.javajeff.cds; public class LinkedListStack implements Stack private static class Node { Object o; Node next; } private Node top = null; public boolean isEmpty () { return top == null; } public Object peek () { if (top == null) throw new java.util.EmptyStackException (); return top.o; } public void push (Object o) { Node temp = new Node (); temp.o = o; temp.next = top; top = temp; } {

public Object pop () { if (top == null) throw new java.util.EmptyStackException (); Object o = top.o; top = top.next; return o; } } LinkedListStack revela una pila como una combinacin de una clase anidada privada de alto nivel llamada Node y una variable de referencia privada top que se inicialia a null para indicar una pila vaca. Al contrario que su contrapartida del array uni-dimensional, LinkedListStack no necesita un constructor ya que se expande dinmicamente cuando se ponen los tems en la pila. As, void push(Object o) no necesita lanzar una FullStackException. Sin embargo, Object pop() si debe chequear si la pila est vaca, lo que podra resultar en el lanzamiento de una EmptyStackException.
Ahora que ya hemos visto el interface y las tres clases que generan mis implementaciones de las pilas, juguemos un poco. El siguiente listado muestra casi todo el soporte de pilas de mi paquete com.javajeff.cds:

// StackDemo.java import com.javajeff.cds.*; class StackDemo { public static void main (String [] args) { System.out.println ("ArrayStack Demo"); System.out.println ("---------------"); stackDemo (new ArrayStack (5)); System.out.println ("LinkedListStack Demo"); System.out.println ("--------------------"); stackDemo (new LinkedListStack ()); } static void stackDemo (Stack s) { System.out.println ("Pushing \"Hello\""); s.push ("Hello"); System.out.println ("Pushing \"World\""); s.push ("World"); System.out.println ("Pushing StackDemo object"); s.push (new StackDemo ()); System.out.println ("Pushing Character object"); s.push (new Character ('C')); System.out.println ("Pushing Thread object"); s.push (new Thread ("A")); try { System.out.println ("Pushing \"One last item\""); s.push ("One last item"); } catch (FullStackException e) { System.out.println ("One push too many");

} System.out.println (); while (!s.isEmpty ()) System.out.println (s.pop ()); try { s.pop (); } catch (java.util.EmptyStackException e) { System.out.println ("One pop too many"); } System.out.println (); } }
Cuando se ejecuta StackDemo, produce la siguiente salida:

ArrayStack Demo --------------Pushing "Hello" Pushing "World" Pushing StackDemo object Pushing Character object Pushing Thread object Pushing "One last item" One push too many Thread[A,5,main] C StackDemo@7182c1 World Hello One pop too many LinkedListStack Demo -------------------Pushing "Hello" Pushing "World" Pushing StackDemo object Pushing Character object Pushing Thread object Pushing "One last item" One last item Thread[A,5,main] C StackDemo@cac268 World Hello One pop too many

Priorizar con Colas

La Cola es una estructura de datos donde la insercin de tem se hace en un final (el fin de la cola) y la recuperacin/borrado de elementos se hace en el otro final (el inicio de la cola). Como el primer elemento insertado es el primero en ser recuperado, los desarrolladores se refieren a estas colas como estructuras FIFO (first-in, first-out). Normalmente los desarrolladores tabajan con dos tipos de colas: lineal y circular. En ambas colas, la insercin de datos se realiza en el fin de la cola, se mueven hacia adelante y se recuperan/borran del incio de la cola. La siguiente figura ilustra las colas lineal y circular:

La cola lineal de la figura anterior almacena cuatro enteros, con el entero 1 en primer lugar. Esa cola est llena y no puede almacenar ms datos adicionales porque rear identifica la parte final de la cola. La razn de la posicin vaca, que identifica front, implica el comportamiento lineal de la cola. Inicialmente, front y rear identifican la posicin ms a la izquierda, lo que indica que la cola est vaca. Para almacenar el entero 1, rear avanza una posicin hacia la derecha y almacena 1 en esa posicin. Para recuperar/borrar el entero 1, front avanza una posicin hacia la derecha. Nota: Para sealar que la cola lineal est vaca, no necesita gastar una posicin, aunque esta aproximacin algunas veces es muy conneniente. En su lugar asigne el mismo valor que indique una posicin no existente a front y a rear. Por ejemplo, asumiendo una implementacin basada en un array uni-dimensional, front y rear podran contener -1. El ndice 0 indica entonces la posicin ms a la izquierda, y los datos se insertarn empezando en este ndice. Cuando rear identifique la posicin ms a la derecha, la cola lineal podra no estar llena porque front podra haber avanzado almenos una posicin para recuperar/borrar un dato. En este esceario, considere mover todos los tems de datos hacia la izquierda y ajuste la posicin de front y rear de la forma apropiada para crear ms espacio. Sin embargo, demasiado movimiento de datos puede afectar al rendimiento, por eso debe pensar cuidadosamente en los costes de rendimiento si necesita crear ms

espacio. La cola circular de la figura anterior tiene siete datos enteros, con el entero 1 primero. Esta cola est llena y no puede almacenar ms datos hasta que front avance una posicin en sentido horario (para recuperar el entero 1) y rear avance una posicin en la misma direcin (para identificar la posicin que contendr el nuevo entero). Al igual que con la cola lineal, la razon de la posicin vaca, que identifica front, implica el comportamiento circular de la cola. Inicialmente, front y rear identifican la misma posicin, lo que indica una cola vaca. Entonces rear avanza una posicin por cada nueva insercin. De forma similar, front avanza una posicin por cada recuperacin/borrado. Las colas son muy tiles en varios escenarios de programacin, entre los que se encuentran:

Temporizacin de Threads: Una JVM o un sistema operativo subyacente podran establecer varias colas para coincidir con diferentes prioridades de los threads. La informacin del thread se bloquea porque todos los threads con una prioridad dada se almacenan en una cola asociada. Trabajos de impresin: Como una impresora normalmente es ms lenta que un ordenador, un sistema operativo maneja los trabajos de impresin en un subsistema de impresin, que inserta esos trabajos de impresin en una cola. El primer trabajo en esa cola se imprime primero, y as sucesivamente.

Los desarrolladores normalmente utilizan una array uni-dimensional para implementar una cola. Sin embargo, si tienen que co-existir mltiple colas o las inserciones en las colas deben ocurrir en posiciones distintas a la ltima por motivos de prioridades, los desarrolladores suelen cambiar a la lista doblemente enlazada. Con un array uni-dimensional dos variables enteras (normalmente llamadas front y rear) contienen los ndices del primer y ltimo elemento de la cola, respectivamente. Mis implementaciones de colas lineales y circulares usan un array uni-dimensional y empiezan con el interface Queue que puede ver en el siguiente listado:

// Queue.java package com.javajeff.cds; public interface Queue { void insert (Object o); boolean isEmpty (); boolean isFull (); Object remove (); } Queue declara cuatro mtodos para almacenar un datos, determinar si la cola est vaca, determinar si la cola
est llena y recuperar/borrar un dato de la cola. Llame a estos mtodos (y a un constructor) para trabajar con cualquier implementacin de Queue. El siguiente listado presenta una a implementacin de Queue de una cola lineal basada en un array unidimensional:

// ArrayLinearQueue.java package com.javajeff.cds; public class ArrayLinearQueue implements Queue { private int front = -1, rear = -1; private Object [] queue;

public ArrayLinearQueue (int maxElements) { queue = new Object [maxElements]; } public void insert (Object o) { if (rear == queue.length - 1) throw new FullQueueException (); queue [++rear] = o; } public boolean isEmpty () { return front == rear; } public boolean isFull () { return rear == queue.length - 1; } public Object remove () { if (front == rear) throw new EmptyQueueException (); return queue [++front]; } } ArrayLinearQueue revela que una cola es una combinacin de variables privadas front, rear, y queue. front y rear se inicializan a -1 para indicar una cola vaca. Igual que el constructor de ArrayStack llama a public ArrayLinearQueue(int maxElements) con un valor entero que especifique el nmero mximo de elementos durante la construccin de un objeto ArrayLinearQueue.
El mtodo insert(Object o) de ArrayLinearQueue lanza una FullQueueException cuando rear identifica el elemento final del array uni-dimensional. El cdigo de FullQueueException aparece en el siguiente listado:

// FullQueueException.java package com.javajeff.cds; public class FullQueueException extends RuntimeException { }


El mtodo remove() de ArrayLinearQueue lanza una EmptyQueueException cuando los objetos front y rear son iguales. El siguiente listado presenta el cdigo de esta clase:

// EmptyQueueException.java package com.javajeff.cds; public class EmptyQueueException extends RuntimeException { }


El siguiente listado presenta una implementacin de Queue para una cola circular basada en un array unidimensional:

// ArrayCircularQueue.java

package com.javajeff.cds; public class ArrayCircularQueue implements Queue { private int front = 0, rear = 0; private Object [] queue; public ArrayCircularQueue (int maxElements) { queue = new Object [maxElements]; } public void insert (Object o) { int temp = rear; rear = (rear + 1) % queue.length; if (front == rear) { rear = temp; throw new FullQueueException (); } queue [rear] = o; } public boolean isEmpty () { return front == rear; } public boolean isFull () { return ((rear + 1) % queue.length) == front; } public Object remove () { if (front == rear) throw new EmptyQueueException (); front = (front + 1) % queue.length; return queue [front]; } } ArrayCircularQueue revela una implementacin, en terminos de variables privadas y un constructor, muy similar a ArrayLinearQueue. El mtodo insert(Object o) es interesante porque guarda el valor actual de rear antes de hacer que esa variable apunte a la siguiente posicin. Si la cola circular est llena, rear restaura su valor original antes de lanzar una FullQueueException. La restauracin de rear es necesaria porque front es igual a rear (en ese punto), y una subsecuente llamada a remove() resulta en la lanzamiento de una EmptyQueueException (incluso aunque la cola circular no est vaca).
Despus de estudiar el cdigo del interface y de varias clases que lo implementan basndose en arrays unidimensionales, consideremos en el siguiente listado una aplicacin que demuestra las colas lineales y circulares:

// QueueDemo.java import com.javajeff.cds.*; class QueueDemo { public static void main (String [] args) { System.out.println ("ArrayLinearQueue Demo"); System.out.println ("---------------------");

queueDemo (new ArrayLinearQueue (5)); System.out.println ("ArrayCircularQueue Demo"); System.out.println ("---------------------"); queueDemo (new ArrayCircularQueue (6)); // Need one more slot because // circular // implementation } static void queueDemo (Queue q) { System.out.println ("Is empty = " + q.isEmpty ()); System.out.println ("Is full = " + q.isFull ()); System.out.println ("Inserting \"This\""); q.insert ("This"); System.out.println ("Inserting \"is\""); q.insert ("is"); System.out.println ("Inserting \"a\""); q.insert ("a"); System.out.println ("Inserting \"sentence\""); q.insert ("sentence"); System.out.println ("Inserting \".\""); q.insert ("."); try { System.out.println ("Inserting \"One last item\""); q.insert ("One last item"); } catch (FullQueueException e) { System.out.println ("One insert too many"); System.out.println ("Is empty = " + q.isEmpty ()); System.out.println ("Is full = " + q.isFull ()); } System.out.println (); while (!q.isEmpty ()) System.out.println (q.remove () + " [Is q.isEmpty () + ", Is full = " + q.isFull () + "]"); try { q.remove (); } catch (EmptyQueueException e) { System.out.println ("One remove too many"); } System.out.println (); } }
Cuando se ejecuta QueueDemo, se produce la siguiente salida:

of

empty

slot

in

empty

"

ArrayLinearQueue Demo --------------------Is empty = true Is full = false Inserting "This" Inserting "is" Inserting "a" Inserting "sentence" Inserting "." Inserting "One last item" One insert too many Is empty = false Is full = true This [Is empty = false, Is full = true] is [Is empty = false, Is full = true] a [Is empty = false, Is full = true] sentence [Is empty = false, Is full = true] . [Is empty = true, Is full = true] One remove too many ArrayCircularQueue Demo --------------------Is empty = true Is full = false Inserting "This" Inserting "is" Inserting "a" Inserting "sentence" Inserting "." Inserting "One last item" One insert too many Is empty = false Is full = true This [Is empty = false, Is full = false] is [Is empty = false, Is full = false] a [Is empty = false, Is full = false] sentence [Is empty = false, Is full = false] . [Is empty = true, Is full = false] One remove too many

Publicado por: Alberto de la Torre Recomendar a un amigo Compartir en redes

Comentarios
Buscar...

BBDD Entornos de desarrollo Entretenimiento Herramientas Internet Lenguajes de script Lenguajes imperativos Lenguajes orientados a objeto Otros lenguajes Plataformas Teora Varios

ltimas noticias
IBM Global Entrepreneur Program: una solucin para poner en marcha tu start up SEO Administrator Presentacin de Play framework 2.0 Anuncio de Play! framework 2.0 en espaol
Ver ms

ltimos artculos
Entity Framework Code First (4) Entity Framework Code First (3) Entity Framework Code First (2) Entity Framework Code First (1)
Ver ms

ltimos cdigos
MessageBox sencillo con JQuery UI Mascara para Text (SWT) Convierte cursor de lectura en cursor de escritura Tres en Raya o Juego del Gato
Ver ms

Copyright 1998-2011 Programacin en Castellano. Todos los derechos reservados Datos legales | Politica de privacidad | Contacte con nosotros | Publicidad Diseo web y desarrollo web. Un proyecto de los hermanos Carrero. Red internet: Juegos gratis | Servidores dedicados Ms internet: Password | Directorio de weblogs | Favicon <p><img alt="Clicky" width="1" height="1" src="http://in.getclicky.com/208180ns.gif" /></p>

Das könnte Ihnen auch gefallen