Вы находитесь на странице: 1из 14

Cap tulo 2 Tipos abstractos de datos (TAD)

Objetivo: Introducir al alumno las estructuras de datos mediante el concepto de tipo abstracto de datos. En este cap tulo se presenta una primera implementacin del TAD Conjunto o y se ir mejorando a lo largo del mismo incluyendo un anlisis de la complea a jidad de los mtodos que lo forman. e

2.1

Introduccin o

Un tipo de datos es una abstraccin que determina un conjunto de valores o que deben tener los datos de cierto tipo. Por ejemplo en los lenguajes de programacin se tienen el tipo entero, real y Booleano. A partir de eso se puede o determinar, por ejemplo, que el 5 es un nmero entero, que true es un valor u Booleano, etc. Adems, los datos tienen ciertas operaciones y propiedades, a por ejemplo sabemos que para nmeros se tienen las operaciones aritmticas u e y para booleanos las operaciones lgicas. Entre las propiedades de estos datos o se cuenta con que los datos forman conjuntos cerrados, por ejemplo una operacin entre dos Booleanos devuelve un booleano. Al considerar tanto datos o como operaciones se tiene un tipo abstracto de datos. Un tipo abstracto de datos (TAD) es un conjunto de datos con sus operaciones. Se denominan TAD porque nada en la denicin indica el cmo se o o implementan las operaciones (por cierto, puede haber ms de una implemena tacin), por tanto en Java para denir TAD se recomienda usar interfaces. o 1

2.2. EL TAD CONJUNTO

Para completar la descripcin de un TAD se debe proporcionar adems de o a la interfaz con las operaciones que se pueden realizar, una descripcin de o las propiedades que deben tener tales operaciones. Un mecanismo util para describir estos aspectos no-sintcticos es el uso de pre/post condiciones. Una a pre-condicin es aquella propiedad que debe satisfacerse antes de la ejecucin o o de un mtodo. Un post-condicin especica propiedades que se deben esperar e o como consecuencia de la ejecucin de un mtodo. o e Por su parte, las estructuras de datos tradicionales son mecanismos utiles para almacenar y recuperar (en/de memoria) colecciones de datos. En Java representan una implementacin de un TAD particular. o

2.2

El TAD Conjunto

Un conjunto puede verse como un tipo de datos donde se puede almacenar cualquier cantidad de datos sin importar el orden y sin posibilidad de repeticin de valores. Las operaciones bsicas con conjuntos son: almacenar o a un dato en l, eliminar un dato, vericar si contiene algn dato particular, e u determinar si el conjunto est vac o su tamao. Adems podr estar las a o n a an operaciones clsicas de interseccin, unin y diferencia. a o o Una forma bonita de denir un TAD es mediante una interfaz, as que para los conjuntos se puede tener la siguiente: public interface Conjuntable { public void agregarElemento(Object elem); public void eliminarElemento(Object elem); public boolean contieneElemento (Object elem); public boolean estVaco(); a public int tama~o(); n ... //Operaciones clsicas con conjuntos. Quedan como ejercicio a } Propiedades que se esperan de un conjunto: agregarElemento. Si el elemento no existe en el conjunto lo agrega al conjunto, aunque no est denida la posicin del nuevo elemento. Si el a o elemento ya se encuentra en el conjunto se dispara una excepcin. En o caso de ser exitosa la operacin el tamao del conjunto crece en una o n unidad.

2.2. EL TAD CONJUNTO

contieneElemento. Regresa true si el elemento est en el conjunto y a false en otro caso. Este mtodo no cambia el estado del conjunto. e eliminarElemento. Si el elemento existe en el conjunto lo elimina, en caso contrario dispara la excepcin NoSuchElementException. En caso o de que la operacin sea exitosa se reduce el tamao del conjunto en una o n unidad. estVacio. Devuelve true si el conjunto est vac y false en otro a a o caso. tama~o. Devuelve un entero que indica la cantidad de elementos en el n conjunto. La interfaz es independiente de la implementacin. A continuacin se o o presenta una implementacin usando arreglos. o /** * Programa que implementa el tipo de datos abstracto conjunto. * @author Amparo Lpez Gaona o * @version Agosto 2007. */ public class Conjunto implements Conjuntable { private Object[] datos; private int indiceFinal; /** Constructor por omisin, crea un conjunto con una capacidad mxima de o a * 20 elementos */ public Conjunto() { datos = new Object[20]; indiceFinal = 0; } /** * Crea un arreglo con capacidad para un conjunto de un mximo determinado a * por el usuario o 20 en caso de proporcionar un nmero negativo. u * @param tam - entero positivo que determina el tama~o mximo del conjunto n a */

2.2. EL TAD CONJUNTO

public Conjunto(int tam) { datos = (tam <= 0) ? new Object [20] : new Object [tam] ; indiceFinal = 0; } /** * Mtodo que determina si un conjunto no tiene elementos. e * @return boolean - true si el conjunto est vaco y false en otro caso. a */ public boolean estVaco(){ a return (indiceFinal == 0); } /** * Mtodo que determina la cantidad de elementos en el conjunto e * @return int - cantidad de elementos en el conjunto. */ public int tama~o(){ n return indiceFinal; } /** * Mtodo que determina si un elemento dado est en el conjunto e a * @param elem - Objeto a buscar * @return boolean - true si el objeto se encuentra en el conjutno y * false en otro caso */ public boolean contieneElemento (Object elem){ if (!estVaco()) a for (int i = 0; i < indiceFinal; i++) if (elem.equals(datos[i])) return true; return false; } /** * Mtodo que permite borrar un elemento del conjunto e * @param elem - Objeto a eliminar

2.2. EL TAD CONJUNTO

*/ public void eliminarElemento(Object elem){ int i = 0; boolean borrado = false; while (i < indiceFinal && ! borrado) if (elem.equals(datos[i])){ // recorre los elemntos del arreglo for (int j = i; j < indiceFinal -1; j++) datos[j] = datos[j+1]; indiceFinal--; borrado = true; } else i++; } /** * Mtodo que permite agregar un elemento del conjunto, si an no est e u a * en l e * @param elem - Objeto a insertar en el conjunto. */ public void agregarElemento(Object elem){ if (! contieneElemento(elem) && indiceFinal < datos.length) datos[indiceFinal++] = elem; }

2.2.1

Anlisis de algoritmos a

En general interesa conocer qu tan ecientes son los mtodos programados, e e es decir estimar el tiempo requerido para ejecutar cada uno. Porque no es deseable ejecutar un programa que tarde un ao en su ejecucin o que requiera n o ms memoria de la disponible. a A primera vista parece sencillo medir la efectividad de un algoritmo en trminos de tiempo, basta que al ejecutar el programa se tome el tiempo que e tarda en correr. Ya sea con un reloj en mano o bien desde el programa. Esto no es muy deseable porque depende de la mquina, an del compilador, en a u que se haya ejecutado el programa. El anlisis de algoritmos es un tcnica que permite caracterizar la ejecua e cin de algoritmos de manera independiente de cualquier plataforma, como

2.2. EL TAD CONJUNTO

pilador o lenguaje. En lugar de medir el tiempo de ejecucin de un programa se mide el o del algoritmo, el cual estar programado en uno o ms mtodos, as que la a a e medida se basa en el examen del tiempo de ejecucin para la invocacin de un o o solo mtodo. Al hacer ms rpido un mtodo se puede mejorar la velocidad e a a e de ejecucin de un programa entero. Generalmente se calcula el tiempo de o ejecucin en el peor caso, porque el mejor caso no aporta nada y el caso o promedio reeja el comportamiento t pico. As que con el peor caso se tiene un estimado de ejecucin con cualquier entrada posible. o Si el mtodo para calcular el tamao de un conjunto fuera el siguiente: e n for (int i = 0; i <datos.length; i++) if (datos[i] == null) return i; return datos.length; y el conjunto tuviera 100 elementos, ser necesario hacer 100 asignaciones a y si cada una se realiza en un tiempo constante c, entonces el mtodo tarda e c 100 unidades de tiempo en realizarse. Si el tamao del arreglo cambia a n n, se requiere que se hagan n asignaciones. En este caso se dice que el tiempo de ejecucin del mtodo depende de la cantidad de datos de entrada, o ms o e a formalmente que se tiene un algoritmo de complejidad O(n) (O grande de n). En caso de que el mtodo estuviera programado como sigue: e public int tama~o(){ n return indiceFinal; } En este caso con una sola instruccin se puede determinar el tamao del o n conjunto. Este algoritmo es mucho mejor que el anterior, porque no depende de la cantidad de datos de entrada, por lo tanto toma un tiempo constante en su ejecucin, as que se dice que es de orden O(1). o En el anlisis de la complejidad de un algoritmo no se incluyen constantes, a es decir, no se dice O(2n2 ) ni O(n2 + n), en ambos casos la forma correcta es O(n2 ). Por ejemplo, si se desea bajar un archivo de n Kbytes que est en a Internet. Si se tarda 3 segundos en establecer la conexin, luego la carga se o realiza a 1.5 Kb/seg, el tiempo requerido se describe como T (n) = n/1,5 + 3, por tanto se tiene una funcin lineal. Si n = 1500 entonces T(n) = 1003 y o

2.2. EL TAD CONJUNTO

T(750) = 503, que es casi la mitad. Luego si se duplica el tiempo de inicio se tiene que T(1500) = 1006 y T(750) = 506, es decir sigue siendo casi la mitad sin importar la constante, por tanto se ignoran las constantes. Funciones comunes Las funciones ms comunes para rango de crecimiento son: a Funcin o c log n log2 n n n n log n n n n2 n3 nd , d > 3 2n n! nombre Constante Logar tmica Log-cuadrtica a Ra cuadrada z Lineal

Cuadrtica a Cubica Polinomial Exponencial Factorial

Ejercicio: Cul es el tiempo de ejecucin de una funcin de cada uno de a o o 5 los grados, si se tiene n = 10 datos de entrada, y se realizan 106 operaciones por segundo. Respuesta: Funcin o log n n n log n n2 n3 2n Qu analizar? e Si se tiene el siguiente mtodo para calcular la suma de los primeros n nmee u ros al cubo y se desea calcular su complejidad. Nombre Logar tmica Lineal Tiempo de ejecucin o 1.2 *105 seg 0.1 seg 1.2 seg Cuadrtica a 2.8 horas Cubica 31.7 aos n Exponencial ms de un siglo a

2.2. EL TAD CONJUNTO

public static int sumanCubos(int n) { int suma; suma = 0; for (int i=1; i < n; i++) suma += i*i*i; return suma; } El tiempo requerido para resolver las declaraciones no cuenta, las asignaciones toman una unidad de tiempo, el cuerpo del for toma cuatro (dos multiplicaciones, una suma y una asignacin) por n veces que se ejecuta da o un total de 4n unidades. El encabezado del for toma una unidad para la inicializacin, n + 1 para las comparaciones y n para el incremento, lo cual o da un total de 2n + 2. Sumado todo nos da un total de 6n + 4, es decir se tiene un mtodo que orden O(n) o sea lineal. e Para evitar hacer esos clculos tan detallados se tienen las siguientes a reglas generales: 1. Asignaciones, declaraciones. Para efectos de clculos se asume que a todas las operaciones sobre tipos primitivos, las asignaciones, las secuencias de asignaciones toman un tiempo constante. 2. Proposiciones consecutivas. Se suman. 3. Condicionales. Se toma el tiempo de la condicin ms el mayor de o a las dos alternativas. if (a > 0) { suma += a; datos++; else a*= (-1); 4. Ciclos. El tiempo de ejecucin de un ciclo es el tiempo de ejecucin de o o su cuerpo por el nmero de veces que se realiza. El caso ms sencillo es u a cuando estn jos los valores de entrada y de salida y el cuerpo toma a un tiempo constante. Ejemplo: for (int i=0; i < n; i++) if (valores[i] < mnimo) mnimo = valores[i];

2.2. EL TAD CONJUNTO

Este ciclo se realiza n veces y el cuerpo toma un tiempo constante cada vez, por tanto el tiempo de ejecucin de este ciclo es O(n). o Cul es el tiempo de ejecucin del siguiente ciclo? a o public boolean esPrimo (int n) { for (int i=2; i*i <= n; i++) if (0 == n %i) return false; return true; } Aqu el ciclo se hace mientras la i sea menor o igual a la ra cuadrada z de n, es decir el nmero mximo de iteraciones es n, como el cuerpo u a del ciclo toma un tiempo constante, se tiene que el algoritmo es O( n). Recordemos que estas medidas representan la ejecucin en el peor caso. o 5. Ciclos anidados. El tiempo de ejecucin de una proposicin dentro o o de un grupo de ciclos anidados es el tiempo de ejecucin de la propoo sicin multiplicado por el producto de los tamaos de todos los ciclos. o n Ejemplo: for (int i = 0; i <n ; i++) for (int j=0; j < n ; j++) k++; Este algoritmo es de orden n2 , porque cada ciclo se realiza n veces y el cuerpo es de orden uno. for (int i = 0; i <n ; i++) for (int j=0; j < n ; j++) { c[i][j] = 0; for (int k=0; k < n ; k++) c[i][j] += a[i][k] * b[k][j]; } El tiempo de ejecucin de este ciclo es O(n3 ). o Cuando los l mites de las iteraciones estn relacionados con los a ndices externos, el anlisis se vuelve ms complejo. a a

2.2. EL TAD CONJUNTO

10

for (int i = for (int j if (v[j] double v[j] = v[j+1] }

n-1; i > 0; i--) = 0; j < i; j++) > v[j+1]) { temp = v[j]; v[j+1]; = temp;

Para determinar el tiempo de ejecucin de este algoritmo notamos que o la iteracin interna se realiza n 1 veces , la segunda n 2 veces, etc. o As el ciclo interno se realiza (n 1) + (n 2) + .. + 1 = ((n 1)n)/2 = (n2 n)/2 por tanto el algoritmo es O(n2 ). 6. Llamadas a mtodos. El tiempo se calcula como el necesario para e realizar tal mtodo. e public void imprimePrimos(int n) { for (int i =2; i <=n; i++) if (esPrimo(i)) System.out.println("valor "+ i + "es primo."); else System.out.println("valor "+ i + "no es primo."); } El mtodo esPrimo tiene un tiempo de ejecucin e o O( n) (como se vi antes) por tanto imprimePrimo es de orden O(n n) o Cuando se suma complejidad algor tmica, el valor mayor es el que predomina y se conserva para el resultado. Por ejemplo O(n2 )+O(n) = O(n2 +n) = O(n2 ). La tabla es la que da las prioridades.

2.2.2

Iteradores

Es tarea comn, recorrer una coleccin o estructura de datos para obtener u o todos los elementos de ella, ya sea para imprimirlos o bien realizar una operacin sobre todos ellos (por ejemplo, incrementar el salario de todos los o empleados, dar de alta un conjunto de alumnos en un curso particular, etc.) Para ello se usa, en general, un for.

2.2. EL TAD CONJUNTO

11

for (int i = 0; i < miArreglo.tama~o(); i++) { n Object v = miArreglo.obtenerElemento(i); ... } Slo que esta forma no es genrica pues depende de obtenerElemento y o e de que se sabe que en la implementacin se utiliza un arreglo. Otra forma o de hacerlo es implementando la interfaz Iterator del paquete java.util presentada a continuacin: o public interface Iterator { public boolean hasNext(); public Object next() throws NoSuchElementException; public void remove() throws IllegalStateException, NoSuchElementException; } As que normalmente las clases que implementan o tienen colecciones incluyen un mtodo que devuelve un conjunto de elementos de una clase que e implementa la interfaz Iterador. El objeto cliente no requiere conocer la organizacin de los datos. En general, se dene como una clase interna, como o se ver en el siguiente ejemplo. a import java.util.*; public class Conjunto implements Conjuntable { // Misma estructura y mtodos que antes ms los mtodos siguientes: e a e public Iterator elementos () { return new datosIndexados(); } private class datosIndexados implements Iterator { private int pos = 0; //Posicin inicial o public datosIndexados(){} Constructor por omisin o public boolean hasNext() { return (pos < nElems); // Determina si an hay elementos en u // el conjunto

2.3. ARREGLOS EXPANDIBLES

12

} public Object next() throws NoSuchElementException { if (hasNext()) // Devuelve el siguiente elemento en el conjunto return datos[pos++]; throw new NoSuchElementException(); } public void remove() throws IllegalStateException, NoSuchElementException { throw new NoSuchElementException(); } } public static void main( String[] xx) { ... System.out.println("Voy a imprimir: "); for (Iterator it = c.elementos(); it.hasNext();) System.out.print((Integer) it.next() + " "); } Denir una clase dentro de otra permite establecer que hay una estrecha relacin entre ambas clases. Una clase interna tiene acceso, sin calicativo, o a todos los mtodos y estructura del objeto que la encierra (an los privae u dos). Se recomienda que la clase interna sea muy sencilla. La clase externa proporciona la mayor de la funcionalidad y la interna, slo funcionalidad a o asociada a la externa pero subordinada a ella.

2.3

Arreglos expandibles

El arreglo es la unica estructura de datos que proporciona Java. La ventaja de los arreglos es que toma el mismo tiempo acceder a cualquier elemento de l, sin embargo no pueden crecer, es costoso insertar o suprimir elemene tos de una coleccin almacenada en un arreglo sin dejar huecos. Es decir, o aunque son sumamente utiles no son apropiados para todos los problemas de almacenamiento de datos.

2.3. ARREGLOS EXPANDIBLES

13

interface ArregloExpandible { public boolean estVacio (); a public int tama~o (); n public void agregarElemento(Object val, int pos); public Object obtenerElemento(int pos); public void eliminarElemento(int pos); public void reemplazarElemento(Object v, int pos); public void ajustarTama~o(int nuevoTama~o) ; n n } La forma de trabajar de los objetos de la clase que implemente la interfaz ArregloExpandible es la siguiente: estVacio. Devuelve true si el arreglo no tiene elementos y false en a otro caso. tama~o. Devuelve un entero que indica la cantidad de elementos alman cenados en el arreglo. agregarElemento. Agrega un elemento al arreglo en la posicin indicao da (sta debe tener un valor menor o igual al tamao del arreglo). Para e n insertar un elemento, se hace un espacio en el arreglo recorriendo los elementos hacia le nal del arreglo. Si el arreglo est lleno, se aumenta a su capacidad. El tamao del arreglo se incrementa en una unidad. n Notar que en este arreglo se tienen dos conceptos, tama~o que es la cann tidad de elementos en l y capacidad que es la cantidad de localidades e que contiene f sicamente el arreglo. Este ultimo dato lo desconoce el usuario.
tamano() Capacidad (datos.length)

0 1 datos

Figura 2.1: Arreglo expandible

2.3. ARREGLOS EXPANDIBLES

14

obtenerElemento. Devuelve el elemento almacenado en la posicin ino dicada, siempre y cuando sea sta sea vlida. Si la posicin es invlida se e a o a dispara la excepcin ArrayIndexOutOfBoundsException. Este mtodo o e no cambia el estado del objeto. eliminarElemento. Elimina el elemento almacenado en la posicin ino dicada, siempre y cuando sea sta sea vlida. Si la posicin es invlida e a o a se dispara la excepcin ArrayIndexOutOfBoundsException. En caso o de que la operacin sea exitosa se reduce el tamao del arreglo en una o n unidad. reemplazarElemento. Sustituye el elemento almacenado en la posicin o indicada por el elemento indicado. Si la posicin es invalida dispara la o excepcin. ArrayIndexOutOfBoundsException. El mtodo no cambia o e el tamao del arreglo. n ajustarTama~o. Aumenta la capacidad del arreglo en el nmero de n u unidades indicado. Este mtodo no altera la cantidad de elementos e almacenados en el arreglo.

Вам также может понравиться