Universidad de Buenos Aires Facultad De Ingenierı́a Introducción al Tipo de Dato Abstracto (TDA) [75.40] Algoritmos y Programación I 2do Cuatrimestre 2010 Cátedra: Ing. Pablo Guarna Autor: Bernardo Ortega Moncada Apunte de TDA 2do Cuatrimestre 2010 Índice 1. Introducción 2 2. ¿Que es la Abstracción? 2 3. Concepto de TDA 3.1. Abstracción al utilizar un TDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2. Abstracción al construir un TDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 3 4. Diseño de un TDA 4.1. Ejemplo de diseño de un TDA . . . . . . 4.1.1. Analizar el problema . . . . . . . . 4.1.2. Obtener caracterı́sticas principales 4.1.3. Realizar diagrama del TDA . . . . 4.1.4. Implementar un TDA . . . . . . . 4.1.5. Testear el TDA . . . . . . . . . . . 3 3 3 3 4 4 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. Observaciones 6 Autor: Bernardo Ortega Moncada 1 Apunte de TDA 1. 2do Cuatrimestre 2010 Introducción Este apunte esta orientado para introducirle al alumno, el concepto del mecanismo de Abstracción y sobre el Tipo de Dato Abstracto (TDA), tengan mucho en mente que este tema es dedicado con mucha profundidad en la materia posterior a esta, es decir lo van a ver con mucho detalle en [75.41]Algoritmos y Programación II 2. ¿Que es la Abstracción? Bueno para arrancar vamos a definir el concepto de Abstracción, este concepto no es muy fácil de entender al principio, pero con tiempo y dedicación, uno logra captarlo. El concepto de la Abstracción o como comúnmente se denomina Mecanismo de Abstracción, en formas generales es la consideración de ciertas partes seleccionadas de un todo complejo, ignorando las partes sobrantes. Bien hasta acá no aportamos mucho a la cuestión, para eso, vamos a aplicarlo a lo nuestro, es decir a un nivel mas Ingenieril. La Abstracción me otorga la posibilidad de considerar una resolución de un cierto problema en el cual, no tenemos idea de como esta resuelto, o demostrado o etc, es decir, que ignoramos todo lo que esta por debajo del nivel que nos interesa. En este caso a nosotros nos interesa solo como se utiliza, lo cual un nivel inferior a lo que nos interesa es el “como esta implementado, o desarrollado, o demostrado, etc” por ende lo descartamos. Es mas podemos citar ejemplos en nuestra vida cotidiana en la cual, aplicamos el mecanismo de Abstracción constantemente sin quizás darnos cuenta que lo hacemos. Como por ejemplo: Al utilizar la televisión, es decir no nos interesa el como funciona, solo sabemos usarla Al utilizar el auto, solo sabemos conducirlo, pero quizás no sabemos su complejo funcionamiento interno Al programar en ciertos lenguajes, utilizamos funciones/procedimientos ya existentes sin saber como fueron construidos etc 3. Concepto de TDA Un TDA o también conocido como Tipo de Dato Abstracto (quizas si leen algun libro que esté en ingles, o buscan por Internet lo pueden encontrar como ADT que en ingles significa, Abstract Data Type) está dado por un grupo de datos(vectores, registros, constantes, etc) que cumplen cierta condición especificada para el TDA, más un conjunto de operaciones que representan el comportamiento del mismo. Es decir que el TDA tiene una identidad y un comportamiento, con el cual permite la interacción (comunicación) con el mismo. Otro punto muy importante y que tienen que saber siempre, es que el TDA es independiente del lenguaje en el que se quiera implementar, es decir, que cierto TDA puede implementarse en P ASCAL, C, C + +, C#, JAV A, etc. El TDA surgió para facilitar el trabajo con tipos de datos haciendo abstracción de la implementación de los mismos. Como verán en el TDA, se aplica el concepto de Abstracción en su totalidad. Es decir se aplica tanto en su utilización como en su construcción. Para eso vamos a analizar este concepto en dos fases. La utilización de un TDA y la construcción de un TDA. 3.1. Abstracción al utilizar un TDA La utilización de un TDA, como se mencionó anteriormente, consiste en saber sobre que tema trata dicho TDA, que tipos de datos utiliza y cuales son las operaciones que ofrece (es decir, sus funciones/procedimientos). Bien usted puede decir: “Ok, pero si yo conozco todo esto, estoy sabiendo como está implementado”. Esta afirmación es común y sepan que esta totalmente Errónea, ya que se como esta compuesto ese TDA, se todas las operaciones que me ofrece, pero no se como fue construido, es decir conozco la INTERFAZ (o el diseño), pero no se como dichas operaciones fueron construidas, que vendrı́a a ser la IMPLEMENTACIÓN. Para citar un ejemplo común es cuando ustedes en PASCAL, utilizan el tipo de dato STRING, como sabrán y buscan en Internet el STRING ofrece muchas rutinas (funciones/procedimientos) con el cual me permiten manipularlo. Pueden fijarse dichas rutinas en el siguiente link: http://www.freepascal.org/docs-html/rtl/sysutils/stringfunctions.html. Entonces podemos decir que STRING es un TDA compuesto por una cadena de caracteres de 255 posiciones cuya rutinas que ofrece son las que aparecen en el link, en las cuales se me informa como se llaman y que es lo que hacen, pero en NINGÚN momento supe cuando ni como fueron programadas. Entonces, al utilizar el TDA STRING, estoy realizando el mecanismo de abstracción, considerando solo el nivel que me interesa (es decir, como funciona y como se utiliza) y descarto todo nivel inferior (en este caso, vendrı́a a ser, como fue programado). Como conclusión, podemos decir que el mecanismo de abstracción se cumple al pie de la letra, al momento de utilizar un TDA. Autor: Bernardo Ortega Moncada 2 Apunte de TDA 3.2. 2do Cuatrimestre 2010 Abstracción al construir un TDA La construcción de un TDA, cambia bastante a diferencia de su utilización al momento de aplicar el mecanismo de abstracción. Para eso vamos primero a recordar lo siguiente: Durante esta materia ustedes sólo creaban software cuyos clientes eran personas comunes, es decir, personas comunes y corrientes que no saben sobre programación, por lo tanto, creaban programas en los cuales, les daban opciones al usuario que ingrese datos o que haga algo o etc, y el usuario seguı́a todos los pasos, como pueden apreciar, ustedes construı́an software, de tal manera que lograban que el usuario se abstraiga del como estaba programado (para el usuario “creado”) y lo utilice sin preocupación, ya que daba fé, que ese programa funcionaba correctamente. Bueno, ahora cuando uno cree un TDA, lo que esta haciendo es exactamente lo mismo. Uno puede estar sorprendido con esta afirmación, ya que le resulta medio raro que un TDA sea un software que lo use un cliente. Pues bien, un TDA es un software, cuyo destinatario o usuario, es en definitiva otro programador, ası́ es, otra persona que sabe programar al igual que ustedes. Por ende al igual que un programa común y corriente, al momento de crear un TDA, ustedes tienen que entregarle al usuario, la documentación correspondiente al mismo, junto con los archivos necesarios para que dicho TDA funcione. Pero al momento de construir un TDA, se tiene que tener un buen diseño previo del mismo. Para eso vamos a ver el concepto de diseño de un TDA. 4. Diseño de un TDA Al momento de diseñar un TDA, lo que se tiene que tener en mente es realizar un modelo del problema a resolver, ¿Como es esto?, Facil!, se tiene que seguir los siguientes pasos: 1. Analizar el problema a plantear 2. Obtener sus caracterı́sticas principales 3. Hacer un diagrama de dicho TDA (como más les resulte cómodo) analizando que tipos de datos, constantes y funciones/procedimientos se puede utilizar 4. Implementarlo (programarlo) en el lenguaje deseado, es decir, el que mas nos convenga (en este caso es PASCAL) 5. Testear el TDA una vez terminado Bueno, ahora para que quede mas claro, vamos a realizar un ejemplo, aplicando este concepto de diseño. 4.1. Ejemplo de diseño de un TDA Supongamos que viene una empresa y nos piden que realicemos un software que realice operaciones con números complejos en su forma binómica. Bien, el cliente solo nos dice eso, ya que lo necesitan para realizar un programa que opere con funciones de variable compleja. Entonces una vez planteado el problema (por parte del cliente) sólo nos resta diseñarlo, siguiendo los pasos que mencioné en la sección 4. 4.1.1. Analizar el problema Analicemos el siguiente problema, nos piden realizar un software, que haga operaciones con números complejos. Bien, ahora solo nos resta aprender (o terminar de recordar) que es un número complejo, para eso consultamos o si no tenemos a quien consultar, buscamos un libro o por Internet, por ejemplo el siguiente link: http://es.wikipedia.org/wiki/N%C3%BAmero_complejo. 4.1.2. Obtener caracterı́sticas principales Una vez analizado podemos resumir al problema, considerando las caracterı́sticas que mas nos importa: Numero Complejo: 1. Un numero complejo es un par ordenado tal que si: z ∈ C entonces z = a + ib, con a y b ∈ R, entonces podemos decir, que un numero complejo se compone en dos partes: Parte Real = <(z) = a Autor: Bernardo Ortega Moncada 3 Apunte de TDA 2do Cuatrimestre 2010 Parte Imaginaria = =(z) = b 2. Las operaciones que puedo realizar con los números complejos son las siguiente: Conjugación: la conjugación de un numero complejo z = a + ib se realiza de la siguiente manera: z = a − ib Suma: la suma de dos números complejos z = a + ib y w = x + iy se realiza de la siguiente manera: z + w = (a + x) + i(b + y) Resta: la resta de dos números complejos z = a + ib y w = x + iy se realiza de la siguiente manera: z − w = (a − x) + i(b − y) Multiplicación: la multiplicación de dos números complejos z = a + ib y w = x + iy se realiza de la siguiente manera: z · w = (ax − by) + i(ay + bx) División: la división de dos números complejos z = a + ib y w = x + iy se realiza de la siguiente manera: ax+by bx−ay z z·w w = w·w = x2 +y 2 + x2 +y 2 i √ Módulo: el módulo de un número complejo z = a + ib se realiza de la siguiente manera: |z| = a2 + b2 4.1.3. Realizar diagrama del TDA Para realizar un diagrama no se necesita mucha complicación, solo resta ver los pasos anteriores y armarlo. En este caso el diagrama queda como si fuese una tabla veamos lo siguiente: TDA Número Complejo unNumeroComplejo : tNumeroComplejo crear numero(var unNumero :tNumeroComplejo ; real,imaginario : REAL) conjugar numero(var unNumero :tNumeroComplejo):tNumeroComplejo calcular modulo(var unNumero :tNumeroComplejo):Real sumar numeros(var unNumero, otroNumero :tNumeroComplejo):tNumeroComplejo restar numeros(var unNumero, otroNumero :tNumeroComplejo):tNumeroComplejo multiplicar numeros(var unNumero, otroNumero :tNumeroComplejo):tNumeroComplejo dividir numeros(var unNumero, otroNumero :tNumeroComplejo):tNumeroComplejo 4.1.4. Implementar un TDA Para implementar dicho TDA, lo vamos a realizar en el lenguaje PASCAL, utilizando lo que se denomina (y ustedes ya conocen) UNITS1 . Entonces solo nos resta crear dicha UNIT. Aclaración: Tengan en cuenta que dicha unit va a estar incompleta, para que ustedes la terminen a modo de ejercicio Unit: TDA Numero Complejo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 UNIT numero complejo ; INTERFACE CONST ERROR DIVISION = 0 ; TYPE tNumeroComplejo = RECORD p a r t e R e a l : REAL; p a r t e I m a g i n a r i a : REAL END; {POST: c r e a un numero c o m p l e j o con l a p a r t e r e a l e i m a g i n a r i a d e s e a d a } PROCEDURE c r e a r n u m e r o ( var unNumero : tNumeroComplejo ; r e a l , i m a g i n a r i o : REAL ) ; {PRE: unNumero t i e n e que e s t a r c r e a d o } 1 Lo pueden chequear también en el apunte teórico que se encuentra en el grupo yahoo de la cátedra llamado Apunte Teórico(Algoritmos I)(VERSIÓN 3) Autor: Bernardo Ortega Moncada 4 Apunte de TDA 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 2do Cuatrimestre 2010 {POST: c o n j u g a e l numero c o m p l e j o d e s e a d o } FUNCTION c o n j u g a r n u m e r o ( var unNumero : tNumeroComplejo ) : tNumeroComplejo ; {PRE: unNumero t i e n e que e s t a r c r e a d o } {POST: d e v u e l v e e l r e s u l t a d o d e l c a l c u l o d e l modulo d e l numero c o m p l e j o d e s e a d o } FUNCTION c a l c u l a r m o d u l o ( var unNumero : tNumeroComplejo ) : Real ; {PRE: unNumero y otroNumero t i e n e n que e s t a r c r e a d o s } {POST: d e v u e l v e un numero c o m p l e j o r e s u l t a d o de l a suma de unNumero y otroNumero } FUNCTION sumar numeros ( var unNumero , otroNumero : tNumeroComplejo ) : tNumeroComplejo ; {PRE: unNumero y otroNumero t i e n e n que e s t a r c r e a d o s } {POST: d e v u e l v e un numero c o m p l e j o r e s u l t a d o de l a r e s t a de unNumero y otroNumero } FUNCTION r e s t a r n u m e r o s ( var unNumero , otroNumero : tNumeroComplejo ) : tNumeroComplejo ; {PRE: unNumero y otroNumero t i e n e n que e s t a r c r e a d o s } {POST: d e v u e l v e un numero c o m p l e j o r e s u l t a d o de l a m u l t i p l i c a c i o n de unNumero y otroNumero } FUNCTION m u l t i p l i c a r n u m e r o s ( var unNumero , otroNumero : tNumeroComplejo ) : tNumeroComplejo ; {PRE: unNumero y otroNumero t i e n e n que e s t a r c r e a d o s , otroNumero t i e n e que s e r d i s t i n t o de 0 + i 0 } {POST: d e v u e l v e un numero d i s t i n t o de ERROR DIVISION a s i g n a n d o a r e s u l t a d o l a d i v i s i o n e n t r e unNumero y otroNumero . Caso c o n t r a r i o d e v u e l v e ERROR RESULTADO} FUNCTION d i v i d i r n u m e r o s ( var unNumero , otroNumero , r e s u l t a d o : tNumeroComplejo ) : byte ; IMPLEMENTATION {PRE: unNumero t i e n e que e s t a r c r e a d o } {POST: d e v u e l v e TRUE s i e l numero c o m p l e j o e s 0 + i0 , c a s o c o n t r a r i o FALSE} { O b s e r v a c i o n : F i j a r s e que d i c h a f u n c i o n no e s t a d e c l a r a d a en INTERFACE, p e r o su c o d i g o s i e s t a en IMPLEMENTATION, h a c i e n d o que d i c h a f u n c i o n s e a de c a r a c t e r p r i v a d o l o c u a l e l c l i e n t e de e s t e TDA, NUNCA podra u s a r l a , ya que jamas s e e n t e r a r a de su e x i s t e n c i a } { Tip : Esta f u n c i o n ‘ ‘ p r i v a d a ’ ’ l e s va a s e r u t i l a l momento de programar l a f u n c i o n dividir numeros } FUNCTION e s c e r o ( var unNumero : tNumeroComplejo ) : b o o l e a n ; VAR r e s u l t a d o : BOOLEAN; BEGIN r e s u l t a d o := FALSE ; IF ( ( unNumero . p a r t e R e a l = 0 ) and ( unNumero . p a r t e I m a g i n a r i a = 0 ) ) THEN r e s u l t a d o := TRUE e s c e r o := r e s u l t a d o END; PROCEDURE c r e a r n u m e r o ( var unNumero : tNumeroComplejo ; r e a l , i m a g i n a r i o : REAL ) ; BEGIN unNumero . p a r t e R e a l := r e a l ; unNumero . p a r t e I m a g i n a r i a := i m a g i n a r i o ; END; FUNCTION c o n j u g a r n u m e r o ( var unNumero : tNumeroComplejo ) : tNumeroComplejo ; VAR aux : tNumeroComplejo ; BEGIN aux . p a r t e R e a l := unNumero . p a r t e R e a l ; aux . p a r t e I m a g i n a r i a := −1 ∗ ( unNumero . p a r t e I m a g i n a r i a ) ; c o n j u g a r n u m e r o := aux ; Autor: Bernardo Ortega Moncada 5 Apunte de TDA 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 2do Cuatrimestre 2010 END; FUNCTION sumar numeros ( var unNumero , otroNumero : tNumeroComplejo ) : tNumeroComplejo ; VAR aux : tNumeroComplejo ; BEGIN aux . p a r t e R e a l := unNumero . p a r t e R e a l + otroNumero . p a r t e R e a l ; aux . p a r t e I m a g i n a r i a := unNumero . p a r t e R e a l + otroNumero . p a r t e I m a g i n a r i a ; sumar numeros := aux ; END; {CONTINUAR DICHA UNIT HASTA COMPLETAR TODAS LAS FUNCIONES/PROCEDIMIENTOS} END. 4.1.5. Testear el TDA Una vez finalizado la implementación del TDA, se tiene que testear, para eso se debe armar un nuevo programa que este dedicado exclusivamente al testeo del TDA (que por cierto el cliente no DEBE enterarse), para eso se debe llamar a la UNIT, y se empieza a manipular las funciones/procedimientos, verificando que hagan lo que tengan que hacer por medio de impresiones por pantalla (utilizando Writeln), lo mas importante es que el testeo tiene que abarcar todas las posibilidades de error en dicho TDA, para asegurarse que funcione correctamente, en caso de haber error, esta demás aclarar que se tiene que reparar el TDA 5. Observaciones Para terminar de cerrar este tema, paso a mostrarles, los puntos claves que tienen que tener en cuenta para saber si diseñaron un buen TDA: El TDA, tiene que modelar solo un tema, es decir que el TDA tiene que resolver solo un problema y no varios a la vez, en este caso, supongamos que tenemos el TDA Número Complejo, dicho TDA, tiene que modelar y resolver las operaciones con números complejos y no dedicarse a otra cosa como modelar y resolver las funciones de variable compleja, ya que eso se encargarı́a otro TDA. Las funciones/procedimientos de los TDA, se denominan “Primitivas” y dichas Primitivas, tienen que contener códigos cortos, no tienen que ser extremadamente largas, una Primitiva con pocas lineas de código, es una Primitiva bien diseñada Todo TDA tiene que tener una primitiva para su “construcción” y (en algunos casos) para su “destrucción” Las primitivas del TDA tienen que permitirle al usuario manipularlo dándole la mı́nima información sobre la implementación del TDA, esto se denomina Ocultamiento de la Información con el cual al usuario solo le informamos de como se compone y que herramientas tiene a la alcance para manipularlo. El ocultamiento de la implementación de las primitivas, es lo que se denomina como Encapsulamiento en el cual ocultamos toda linea de código existente en dicho TDA. El testeo del TDA tiene que ser 100 % exitoso Autor: Bernardo Ortega Moncada 6