jueves, 4 de noviembre de 2010

COLAS DOBLES Y CIRCULARES

Cola dobles

La bicola o doble cola es un tipo de cola especial que permiten la inserción y eliminación de elementos de ambos extremos de la cola. Puede representarse a partir de un vector y dos índices, siendo su representación más frecuente una lista circular doblemente enlazada.
Esta estructura es una cola bidimensional en que las inserciones y eliminaciones se pueden realizar en cualquiera de los dos extremos de la bicola. Gráficamente representamos una bicola de la siguiente manera:


Existen dos variantes de la doble cola:
  • Doble cola de entrada restringida.
  • Doble cola de salida restringida.
La primera variante sólo acepta inserciones al final de la cola, y la segunda acepta eliminaciones sólo al frente de la cola
Algoritmo de Inicialización
               F < -- 1
               A <-- 0

Algoritmo para Insertar
               Si A=máximo entonces
                        mensaje (overflow)
               en caso contrario
                        A <--A+1
                        cola[A]<-- valor

Algoritmo para Extraer
               Si F&gtA entonces
                        mensaje (underflow)
               en caso contrario
                        mensaje (frente/atrás)
                               si frente entonces
                                      x <-- cola[F]
                                      F <-- F+1
                               en caso contrario
                                      x <-- cola[A]
                                      A <-- A-1


Esta estructura es un conjunto de elementos donde a cada uno de ellos se les asigna una prioridad, y la forma en que son procesados es la siguiente:
  1. Un elemento de mayor prioridad es procesado al principio.
  2. Dos elementos con la misma prioridad son procesados de acuerdo al orden en que fueron insertados en la cola.

Algoritmo para Insertar
               x <--1
               final<--verdadero
               para i desde 1 hasta n haz
                       Si cola[i]&gtprioridad entonces
                               x <--i
                               final <--falso
                               salir
                               si final entonces
                                       x <--n+1
                               para i desde n+1 hasta x+1
                                       cola[i] <--prioridad
                                       n <-- n+1

Algoritmo para Extraer
               Si cola[1]=0 entonces
                       mensaje(overflow)
               en caso contrario
                        procesar <--cola[1]
                        para i desde 2 hasta n haz
                               cola[i-1] <--cola[1]
                               n <-- n-1


Las operaciones que nosotros podemos realizar sobre una cola son las siguientes:
·         Inserción.
·         Extracción.
Las inserciones en la cola se llevarán a cabo por atrás de la cola, mientras que las eliminaciones se realizarán por el frente de la cola (hay que recordar que el primero en entrar es el primero en salir).

Existen dos variantes de la doble cola:

Doble cola de entrada restringida.-
Este tipo de doble cola acepta solamente la inserción de elementos por un extremo; mientras que puede eliminar por ambos.

Doble cola de salida restringida.-
Este tipo de doble cola acepta solamente la eliminación de elementos por un extremo; mientras que puede insertar por ambos.

Cola Circular


Una cola circular o anillo es una estructura de datos en la que los elementos están de forma circular y cada elemento tiene un sucesor y un predecesor. Los elementos pueden cosultarse, añadirse y eliminarse unicamente desde la cabeza del anillo que es una posición distinguida. Existen dos operaciones de rotaciones, una en cada sentido, de manera que la cabeza del anillo pasa a ser el elemento sucesor, o el predecesor, respectivamente, de la cabeza actual.
Para solucionar el problema de desperdicio de memoria se implementaron las colas circulares, en las cuales existe un apuntador desde el último elemento al primero de la cola.
La representación gráfica de esta estructura es la siguiente:

La condición de vacío en este tipo de cola es que el apuntador F sea igual a cero.
Las condiciones que debemos tener presentes al trabajar con este tipo de estructura son las siguientes:
·         Over flow, cuando se realice una inserción.
·         Under flow, cuando se requiera de una extracción en la cola.
·         Vacio

ALGORITMO DE INICIALIZACIÓN

               F < -- 0
               A<-- 0

ALGORITMO PARA INSERTAR

               Si (F+1=A) ó (F=1 y A=máximo) entonces
                       mensaje (overflow)
               en caso contrario
                       inicio
                               si A=máximo entonces
                                       A<--1
                                       cola[A]<-- valor
                               en caso contrario
                                       A <--A+1
                                        cola[A]<-- valor
                               si F=0 entonces
                                        F <-- 1
                        fin

ALGORITMO PARA EXTRAER

               Si F=0 entonces
                       mensaje (underflow)
               en caso contrario
                       x <-- cola[F]
                        si F=A entonces
                               F <-- 0
                               A<-- 0
                        en caso contrario
                               si F=máximo entonces
                                       F <--1 en caso contrario F <-- F+1

Primera versión:
Esta versión requiere el uso de la operación módulo de la división para determinar la siguiente posición en el array.
Por ejemplo, supóngase un array de N = 2 elementos, contando desde 0 hasta 1. Suponer que entrada = 0, salida = 1; Para determinar la posición siguiente del índice i en el array se procede así:
i <- (i+1) Mod N
siendo Mod la operación resto de la división entera. Asi:
- sustituyendo i por salida se determina que salida = 0.
- sustituyendo i por entrada se determina que entrada = 1.
Nota: si el array está indexado entre 1 y N -como suele ser habitual en Pascal- entonces la expresión que determina la posición siguiente es esta:
i <- (i Mod N) + 1
si entrada = 1, salida = 2, entonces:
- sustituyendo i por salida se determina que salida = 1.
- sustituyendo i por entrada se determina que entrada = 2.

De esta manera se van dando vueltas sobre el array. La lógica es la siguiente:
Para encolar: se avanza el índice entrada a la siguiente posición, y se encola en la posición que apunte éste.
Para desencolar: el elemento desencolado es el que apunta el índice salida, y posteriormente se avanza salida a la siguiente posición.
Cola vacía: la cola está vacía si el elemento siguiente a entrada es salida, como sucede en el ejemplo anterior.
Cola llena: la cola está llena si el elemento que sigue al que sigue a entrada es salida.
Esto obliga a dejar un elemento vacío en el array, puesto que se reserva una posición para separar los índices entrada y salida.
Para aclararlo, se muestran una serie de gráficos explicativos, partiendo de un array de tres elementos, es decir, una cola de DOS elementos.
- Declaración:
struct tcola
{
  int entrada, salida;
  int elementos[MAX_COLA];
};
Una cola que tenga un elemento requiere que MAX_COLA = 2.

- Función que devuelve la posición siguiente a i en el array circular.
int siguiente(int i)
{
  return ((i+1) % MAX_COLA);
}

- Creación:
void crear(struct tcola *cola)
{
  cola->salida = 0;
  cola->entrada = MAX_COLA - 1;
}

- Función que devuelve verdadero si la cola está vacía, cosa que ocurre cuando el siguiente tras entrada es salida:
int vacia(struct tcola *cola)
{
  return (siguiente(cola->entrada) == cola->salida);
}

- Función que devuelve verdadero si la cola está llena, caso que se da cuando el siguiente elemento que sigue a entrada es salida:
int llena(struct tcola *cola)
{
  return (siguiente(siguiente(cola->entrada)) == cola->salida);
}

- Encolado:
void encolar(struct tcola *cola, int elem)
{
  cola->entrada = siguiente(cola->entrada);
  cola->elementos[cola->entrada] = elem;
}

- Desencolado:
void desencolar(struct tcola *cola, int *elem)
{
  *elem = cola->elementos[cola->salida];
  cola->salida = siguiente(cola->salida);
}

miércoles, 20 de octubre de 2010

pilas y colas

Pilas y colas
Una  pila es un caso especial de lista en la cual todas las inserciones y supresiones tienen lugar en un extremo determinado llamado tope. A las pilas se les llama también listas LIFO (last-in first-out) o listas “primero en entrar, primero en salir”. Al igual que ocurría con el TDA Cola, en el TDA Pila tampoco se definen operaciones de posicionamiento en la pila. Esto es debido a que todas las operaciones de acceso se realizan en la misma posición, el tope de la pila.
Para el manejo de los datos se cuenta con dos operaciones básicas: apilar (push), que coloca un objeto en la pila, y su operación inversa, retirar (o desapilar, pop), que retira el último elemento apilado. En cada momento sólo se tiene acceso a la parte superior de la pila, es decir, al último objeto apilado (denominado TOS, Top of Stack en inglés). La operación retirar permite la obtención de este elemento, que es retirado de la pila permitiendo el acceso al siguiente (apilado con anterioridad), que pasa a ser el nuevo TOS.
Por analogía con objetos cotidianos, una operación apilar equivaldría a colocar un plato sobre una pila de platos, y una operación retirar a retirarlo.
Las pilas suelen emplearse en los siguientes contextos:
El método de pila para la evaluación de expresiones fue propuesto en 1955 y dos años después patentado por Fiedrich L.Bauer, quién recibió en 1988 el premio "IEEE Computer Society Pioneer Award" por su trabajo en el desarrollo de dicha estructura de datos.
La pila de llamadas es un segmento de memoria que utiliza esta estructura de datos para almacenar información sobre las llamadas a subrutinas actualmente en ejecución en un programa en proceso.
Cada vez que una nueva subrutina es llamada, se apila una nueva entrada con información sobre ésta tal como sus variables locales. En especial, se almacena aquí el punto de retorno al que regresar cuando esta subrutina termine (para volver a la subrutina anterior y continuar su ejecución después de esta llamada)..

Ejemplos de pilas en java
public class PilaUtil {

   static public void imprimir(Pila pila) {
        try {
            Pila pilaAux = duplicar(pila);
            while (!pilaAux.vacia()) {
                Object e = pilaAux.tope();
                pilaAux.pop();
                System.out.print(e+" ");
            }
            System.out.println();
        } catch (PilaException e) {
            System.err.println("Error en el uso de la Pila: "+e);
        }
    } // fin imprimir()








public class Pila <Tipo> {
    private int     size;
   
private Vector<Tipo>    elementos;
    public Pila() {
        super();
        elementos =
new Vector<Tipo>();
        size = 0;
    }
   
   
public boolean pilaVacia () {
        if (size==0) {
           
return true;
        }
       
return false;
    }
    public void apilar ( Tipo o ) {
        elementos.add(size, o);
        size++;
    }
    public Tipo desapilar () {
        try {
            if(pilaVacia())
               
throw new ErrorPilaVacia();
            else {
               
return elementos.get(--size);
            }
        }
catch(ErrorPilaVacia error) {
            System.out.println("ERROR: la pila esta vacía");
           
return null;
        }
    }
    public int getSize() {
       
return size;
    }
   
}
@SuppressWarnings("serial")class ErrorPilaVacia extends Exception {
   
public ErrorPilaVacia() {
        super();
    }
}
Cola
Una cola es una estructura de datos, caracterizada por ser una secuencia de elementos en la que la operación de inserción push se realiza por un extremo y la operación de extracción pop por el otro. También se le llama estructura FIFO (del inglés First In First Out), debido a que el primer elemento en entrar será también el primero en salir.
Las colas se utilizan en sistemas informáticos, transportes y operaciones de investigación (entre otros), dónde los objetos, personas o eventos son tomados como datos que se almacenan y se guardan mediante colas para su posterior procesamiento. Este tipo de estructura de datos abstracta se implementa en lenguajes orientados a objetos mediante clases, en forma de listas enlazadas.
la particularidad de una estructura de datos de cola es el hecho de que sólo podemos acceder al primer y al último elemento de la estructura. Así mismo, los elementos sólo se pueden eliminar por el principio y sólo se pueden añadir por el final de la cola.
Ejemplos de colas en la vida real serían: personas comprando en un supermercado, esperando para entrar a ver un partido de béisbol, esperando en el cine para ver una película, una pequeña peluquería, etc. La idea esencial es que son todos líneas de espera.
En estos casos, el primer elemento de la lista realiza su función (pagar comida, pagar entrada para el partido o para el cine) y deja la cola. Este movimiento está representado en la cola por la función pop o desencolar. Cada vez que otro elemento se añade a la lista de espera se añaden al final de la cola representando la función push o encolar. Hay otras funciones auxiliares para ver el tamaño de la cola (size), para ver si está vacía en el caso de que no haya nadie esperando (empty) o para ver el primer elemento de la cola (front).

Colas en JAVA

    public void inserta(Elemento x) {
        Nodo Nuevo;
        Nuevo = new Nodo(x, null);
        if (NodoCabeza == null) {
            NodoCabeza = Nuevo;
        } else {
            NodoFinal.Siguiente = Nuevo;
        }
        NodoFinal = Nuevo;
    }
 
    public Elemento cabeza() throws IllegalArgumentException {
        if (NodoCabeza == null) {
            throw new IllegalArgumentException();
        } else {
            return NodoCabeza.Info;
        }
    }
 
    public Cola() {
    // Devuelve una Cola vacía
        NodoCabeza = null;
        NodoFinal = null; 
      



Tipos de colas
  • Colas de prioridad: En ellas, los elementos se atienden en el orden indicado por una prioridad asociada a cada uno. Si varios elementos tienen la misma prioridad, se atenderán de modo convencional según la posición que ocupen. Hay 2 formas de implementación:
  1. Añadir un campo a cada nodo con su prioridad. Resulta conveniente mantener la cola ordenada por orden de prioridad.
  2. Crear tantas colas como prioridades haya, y almacenar cada elemento en su cola.
  • Bicolas: son colas en donde los nodos se pueden añadir y quitar por ambos extremos; se les llama DEQUE (Double Ended QUEue). Para representar las bicolas lo podemos hacer con un array circular con Inicio y Fin que apunten a cada uno de los extremos. Hay variantes:
  • Bicolas de entrada restringida: Son aquellas donde la inserción sólo se hace por el final, aunque podemos eliminar al inicio ó al final.
  • Bicolas de salida restringida: Son aquellas donde sólo se elimina por el final, aunque se puede insertar al inicio y al final.

Las excepciones para Cola:

package pilaException;
public class PilaException extends Exception {
    public PilaException() { super(); };
    public PilaException(String s) { super(s); };
}

package pilaException;
public class PilaVaciaException extends PilaException {
    public PilaVaciaException() { super(); };
    public PilaVaciaException(String s) { super(s); };  
}

import pilaInterface.*;
import pilaException.*;
import java.io.*;