360 likes | 623 Views
Tema 2 Tipos abstractos de datos. 2.3 Cola de números enteros. TAD COLA DE ENTEROS. desencolar. encolar. Especificación de TAD’s. TAD Cola de Enteros. Definición del TAD Cola de Enteros :
E N D
Tema 2 Tipos abstractos de datos. 2.3 Cola de números enteros.
desencolar encolar Especificación de TAD’s. TAD Cola de Enteros. • Definición del TAD Cola de Enteros: • Estructura de Datos que contiene una serie de elementos de tipo entero en la que dichos elementos son insertados por un lado y son extraídos por el lado contrario. • Característica: Primer elemento obtenido es el primero introducido • Estructura FIFO (First Input, First Output) • Operaciones: • encolar. • desencolar. • colaVacia. 3 2 5 3 1
Excepciones. • Excepción: circunstancia que produce que una Operación Válida sobre un TAD no pueda ser efectuada. • Ejemplos: • encolar: • Al intentar encolar un nuevo elemento en la cola, ésta está llena: la operación encolar no debe producir ningún efecto. No se contempla tratamiento alguno. • desencolar, primero, quitarPrimero, invertirCola: • Al intentar realizar una de estas operaciones, la cola está vacía: se producirá un mensaje de error.
Interfaz del TAD Cola import java.io.*; publicinterface Cola { void inicializarCola (); void encolar (int x); int desencolar (); boolean colaVacia (); void leerCola () throws NumberFormatException, IOException; void imprimirCola (); void invertirCola (); int numElemCola (); int primero (); void quitarPrimero (); void eliminarCola (); } Define los métodos de objeto utilizados en la clase TadCola
Condiciones normales y excepcionales de la cola public class PruebaCola2 { public static void main (String[] args) { Cola cola1 = new TadCola (); int i, j; cola1.inicializarCola (); for (i = 1; i< 10; i++) cola1.encolar (i); j = cola1.desencolar (); System.out.println ("Hemos sacado "+j); for (i = 1; i< 10; i++) { j = cola1.desencolar (); System.out.println (“Sacamos "+j); } cola1.eliminarCola (); } } public class PruebaCola1 { public static void main (String[] args) { Cola cola1 = new TadCola (); int elem; cola1.inicializarCola (); cola1.encolar (8); cola1.encolar (7); cola1.encolar (9); cola1.encolar (11); elem = cola1.desencolar (); elem = cola1.desencolar (); System.out.println (“Sale el número"+elem); cola1.eliminarCola (); } }
Estrategias con Colas • Desencolar – llamada recursiva – Encolar • Devuelve la cola invertida • Para usar este esquema, se debe invertir previa o posteriormente los elementos de la cola (fuera del módulo recursivo) • Desencolar – Encolar – llamada recursiva • No se alcanza la condición de finalización Estructura Vacía • Si se conoce el número de elementos • Variable auxiliar que determina la condición de parada • Permite Tratamiento recursivo y iterativo
Invertir una cola • Método (estático) auxiliar en el tratamiento recursivo de colas. static void invertir (Cola cola) { int elem; if (!cola.colaVacia ()) { elem = cola.desencolar (); invertir (cola); cola.encolar (elem); } }
if (!cola.colaVacia () { elem = cola.desencolar (); invertir (cola); 4 5 4 3 2 5 4 2 5 4 elem = 2 elem = 5 elem = 4 elem = 3 cola.encolar (elem); } 4 5 2 3 4 5 2 4 4 5
Contar los elementos de una cola public class PruebaContar { static int contarCola (Cola cola) { int elem, resul; if (!cola.colaVacia ()) { elem = cola.desencolar (); resul = 1 + contarCola (cola); cola.encolar (elem); } else resul = 0; return resul; } static int cuentaCola(Cola cola) { cola.invertirCola (); return contarCola (cola); } public static void main(String[] args) { Cola c = new TadCola (); c.leerCola (); System.out.println ("La cola tiene “+cuentaCola (c)+" elementos"); c.imprimirCola (); } } • La solución recursiva es la única posibilidad: método (estático) contarCola • Necesidad de invertir la cola fuera del módulo recursivo: método (estático) cuentaCola.
Obtener una cola a partir de otra • Estrategias para trabajar con colas: • ¿No se conoce el número de elementos? • Solución recursiva (requiere inversión de la cola) • ¿Se conoce el número de elementos? • Solución recursiva • Solución iterativa
Sin conocer el número de elementos. Solución Recursiva static void copiar (Cola colaO, Cola colaD) { int elem; if (!colaO.colaVacia ()) { elem = colaO.desencolar (); colaD.encolar (elem); copiar (colaO, colaD); colaO.encolar (elem); } } static void copia (Cola colaO, Cola colaD) { copiar (colaO, colaD); colaO.invertirCola (); } public static void main (String [] args) { Cola cO = new TadCola (); Cola cD = new TadCola (); cO.leerCola (); copia (cO, cD); System.out.println ("Cola origen:"); cO.imprimirCola (); System.out.println ("Cola destino:"); cD.imprimirCola (); }
colaO 2 5 3 5 3 3 2 5 3 colaD 3 3 2 3 2 5 elem = 2 elem = 5 elem = 3 if (! colaO.colaVacia ()) { elem = colaO.desencolar (); colaD.encolar (elem); copiar (colaO, colaD); 3 3 2 5 3 elem = 3 colaO.encolar (elem); } 3 5 2 3 3 5 2 3 3 5
Conociendo el número de elementos. Solución Recursiva static void copiaR2 (Cola colaO, Cola colaD, int n) { int elem; if (n > 0) { elem = colaO.desencolar (); colaD.encolar (elem); colaO.encolar (elem); copiar2 (colaO, colaD, n-1); } } public static void main (String[] args) { Cola cO = new TadCola (); Cola cD = new TadCola (); cO.leerCola (); copiaR2 (cO, cD, cO.numElemCola ()); System.out.println ("Cola origen:"); cO.imprimirCola (); System.out.println ("Cola destino:"); cD.imprimirCola (); }
if (n > 0) { elem = colaO.desencolar (); colaD.encolar (elem); colaO.encolar (elem); CopiaR2 (colaO, colaD, n-1); } colaO 2 2 2 2 3 5 4 5 4 3 5 4 3 4 3 5 5 2 2 2 3 2 4 5 4 3 5 4 3 4 3 5 colaD 2 5 2 5 3 4 3 2 3 3 n =2 elem = 5 n = 4 elem = 3 n = 1 elem = 4 n =3 elem = 2
Conociendo el número de elementos. Solución iterativa static void copiaIt (Cola colaO, Cola colaD) { int elem, i, n; n = colaO.numElemCola (); for (i = 1; i <= n; i++) { elem = colaO.desencolar (); colaD.encolar (elem); colaO.encolar (elem); } } public static void main (String [] args) { Cola cO = new TadCola (); Cola cD = new TadCola (); cO.leerCola (); copiaIt (cO, cD); System.out.println ("Cola origen:"); cO.imprimirCola (); System.out.println ("Cola destino:"); cD.imprimirCola (); }
Insertar un elemento al principio de la cola static void InsertarPI (Cola cola, int dato) { int elem, i, n; n = cola.numElemCola (); cola.encolar (dato); for (i = 1; i <= n; i++) { elem = cola.desencolar (); cola.encolar (elem); } }
Terminación anticipada • Precauciones: • Devolver la cola en su estado original • Si hay terminación anticipada • Todos los elementos deben sufrir el proceso de encolar-desencolar • Si no fuese así, el resultado sería una cola con una parte ordenada y otra invertida
Buscar un elemento (sin conocer n) static boolean esta (Cola cola, int dato) { int elem; boolean resul; if (!cola.colaVacia ()) { elem = cola.desencolar (); if (elem == dato) { resul = true; cola.invertirCola (); } else resul = esta (cola, dato); cola.encolar (elem); } else resul = false; return resul; } static boolean estaR1 (Cola cola, int dato) { cola.invertirCola (); return esta (cola,dato); } • Se pasa al módulo recursivo la cola invertida • En el módulo recursivo: • Desencolar-encolar invierte los elementos procesados • Resto de elementos requieren inversión
Buscar un elemento (n conocido, recursivo) static boolean recorrer (Cola cola, int n) { boolean resul; int elem; if (n > 0) { elem = cola.desencolar (); cola.encolar (elem); resul = recorrer (cola, n-1); } else resul = true; return resul; } static boolean estaR2 (Cola cola, int n, int dato) { int elem; boolean resul; if (n > 0) { elem = cola.desencolar (); cola.encolar(elem); if (elem == dato) resul = recorrer (cola, n-1); else resul = estaR2 (cola, n-1, dato); } else resul = false; return resul; }
Buscar un elemento (n conocido, iterativo) static boolean estaIt (Cola cola, int dato) { int n,elem,i; boolean resul; resul = false; n = cola.numElemCola(); while ((n > 0) && (!resul)) { elem = cola.desencolar (); cola.encolar (elem); if (elem == dato) resul = true; n = n-1; } for (i = 1; i <= n; i++) { elem = cola.desencolar (); cola.encolar (elem); } return resul; }
Obtener elemento final de una cola static int quitarUlt (Cola cola) { int elem,dato = -9999; if (!cola.colaVacia ()) { elem = cola.desencolar (); if (!cola.colaVacia ()) { dato = quitarUlt (cola); cola.encolar (elem); } else dato = elem; } return dato; } static int quitarUltimoR1 (Cola cola) { int resul; resul = quitarUlt (cola); cola.invertirCola (); return resul; } Ejercicio propuesto: obtener el elemento final de la cola conociendo el número de elementos
Combinar dos colas. General. • Dos colas ordenadas (c1 y c2) -> c3 ordenada • Se plantean dos posibilidades: • Sin conocer el número de elementos • Conociendo el número de elementos • Solución recursiva. • Solución iterativa.
Combinar dos colas sin conocer el número de elementos. • El mismo algoritmo que con pilas pero devolvería las colas de entrada invertidas. public static void main (String [] args) throws NumberFormatException,IOException { Cola c1 = new TadCola (); Cola c2 = new TadCola (); Cola c3 = new TadCola (); c1.leerCola (); c2.leerCola (); c1.invertirCola (); c2.invertirCola (); mezclar** (c1, c2, c3, false, false, 0, 0); }
Combinar dos colas conociendo el número de elementos. Técnica recursiva. • Técnica empleada: • Método inicial (si procede) no recursivo. • Prepara los dos elementos primeros de cada cola (desencolar-encolar). • Prototipo: mezcla** (cola1, cola2, cola3, elem1, elem2, n1-1, n2-1); • Metodo recursivo: • Condición de terminación: !((n1 >= 0) && (n2 >= 0)) • Tratamiento específico: • Fase de transición. • Terminación anticipada.
Combinar dos colas conociendo el número de elementos. Técnica recursiva. Mezcla AND. • Fase de ida: • Comparar elem1 y elem2. • Si elem1 = elem2, encolar en c3. • [Si se puede] desencolar –encolar elem1|2 de c1|c2 según el caso. • Llamada recursiva con n1-1|n2-1 según el caso. • Fase de transición: • Uso de un procedimiento auxiliar que reordena la cola no finalizada. • Fase de vuelta: • Sin tratamiento.
Combinar dos colas conociendo el número de elementos. Técnica recursiva. Mezcla OR. • Fase de ida: • Comparar elem1 y elem2. • Encolar en c3elem1|2 . • [Si se puede] desencolar –encolar elem1|2 de c1|c2 según el caso. • Llamada recursiva con n1-1|n2-1 según el caso. • Fase de transición: • Encolar en c3 el elemento en pendiente • Uso de un procedimiento auxiliar que: • Reordena la cola no finalizada. • Encola en c3. • Fase de vuelta: • Sin tratamiento.
MÓDULO NO RECURSIVO c3.inicializarCola(); n1 = c1.numElemCola (); n2 = c2.numElemCola (); n1=3 n2=3 mezclaOR_R2 (c1, c2, c3, elem1, elem2, n1-1, n2-1) n1 = 2, n1 = 2, Si ((n1 >= 0) && (n2 >= 0)) Comparo elementos Si elem2 < elem1 cola3.encolar( elem2) Si quedan por tratar en ambas ( (n1 >= 0) && (n2 >= 0)) se obtienen los valores de elem1 y elem2: elem1 = cola1.desencolar (); cola1.encolar (elem1); elem2 = cola2.desencolar (); cola2.encolar (elem2); 4 2 6 1 1 3 5 Se obtiene un nuevo valor para elem2 if (n2>0) { cola2.desencolar (elem2); cola2.encolar (elem2); } 4 2 6 elem1 = 2 elem2 =1 4 2 6 3 5 1 elem1 = 2 elem2 = 3 3 5 1 Se llama al módulo recursivo con n1-1 y n2-1: mezclaOR_R2 (cola1, cola2, cola3, elem1, elem2, n1-1, n2-1); Nueva llamada recursiva con n2-1 mezclarOR_R2 (c1, c2, c3, elem1, elem2, n1, n2-1) n1 = 2; n2 = 1
mezclaOR_R2 (cola1, cola2, cola3, elem1, elem2, n1-1, n2) n1=1;n2=1 mezclaOR_R2 (cola1, cola2, cola3, elem1, elem2, n1, n2-1) n1=2;n2=1 Si ((n1 >= 0) && (n2 >= 0)) Comparo elementos if (elem1 < elem2) cola3.encolar (elem1); Si ((n1 >= 0) && (n2 >= 0)) comparo elementos if (elem2 < elem1) cola3.encolar (elem2); 1 2 1 2 3 Se obtiene un nuevo valor para elem1 if (n1>0) { elem1 = cola1.desencolar (); cola1.encolar (elem1); } Se obtiene un nuevo valor para elem2 if (n2>0) { elem2 = cola2.desencolar (); cola2.encolar (elem2); } 2 6 4 elem1 = 4 elem2 = 5 2 4 6 elem1 = 4 elem2 = 3 3 1 5 3 5 1 Nueva llamada recursiva con n1-1 Nueva llamada recursiva con n2-1
mezclaOR_R2 (cola1,cola2,cola3,elem1,elem2,n1,n2-1) n1=1;n2=0 mezclaOR_R2 (cola1,cola2,cola3,elem1,elem2,n1-1,n2) n1=0;n2=0 Si ((n1 >= 0) && (n2 >= 0)) Comparo elementos if (elem1 < elem2) cola3.encolar (elem1) Si ((n1 >= 0) && (n2 >= 0)) Comparo elementos if (elem2 < elem1) cola3.encolar (elem2) 1 2 3 4 1 2 3 4 5 Se obtiene un nuevo valor para elem1 if (n1>0) { elem1 = cola1.desencolar (); cola1.encolar (); } n2 = 0 → No se puede realizar el proceso de desencolar/encolar sobre cola2 Nueva llamada recursiva con n2-1 2 6 4 elem1 = 6 elem2 = 5 3 5 1 Nueva llamada recursiva con n1-1
mezclaOR_R2 (cola1, cola2, cola3, elem1, elem2, n1-1, n2) n1 = 0; n2 = -1 FASE DE TRANSICIÓN → Se encola el elemento pendiente (si queda alguno) en cola3 → Se llama a un procedimiento auxiliar que copia una cola en otra y restaura la pendiente if (n1 > 0) { elem = cola1.desencolar (); cola1.encolar (elem); cola3.encolar (elem); copiarcola (cola1, cola3, n-1); } 1 2 3 4 5 6
Combinar dos colas con terminación anticipada.Mezcla AND conociendo el número de elementos. Técnica recursiva. • Módulo inicial (no recursivo). • Contempla situaciones de excepción. • Invoca (si procede) al módulo recursivo. (Igual que en la mezcla AND). • Módulo recursivo: • Terminación pesimista: !((n1 >= 0) && (n2 >= 0)). • Análisis de casos posibles. • Reordenar la cola pendiente (si hay alguna). • Terminación anticipada: Si elem1 > elem2. • Devuelve false. • Reordenar ambas colas mediante el método auxiliar. • Resto. Similar a la mezcla AND.