Vous êtes sur la page 1sur 12

1 Tipos Abstractos de Datos (TDA)

Hasta ahora se ha trabajado con tipos de datos primitivos y arreglos. Los Tipos
de Datos Abstractos (TDA) nos permiten realizar una mayor abstraccion de las
cosas que existen en el mundo real, pues nos permiten olvidar detalles sobre
implementaciones y mantener la esencia.
Cuando se tiene un tipo de dato primitivo como los enteros, se tiene la
denicion de entero Z, que representa datos de tipo entero. En los enteros,
se tienen denidas las operaciones aritmeticas +, , , /, mod que nos permiten
realizar operaciones con este tipo de datos sin conocer como se esta realizando
una suma o una division a nivel de maquina.
En este libro se denieron funciones de lectura y escritura a ujos de datos
para enteros. Una vez denida la funcion si otra persona desea utilizarla lo unico
que debe hacer es llamar a la funcion e ignorar los detalles implementacion de
la funcion en si.
2 Estructura y Operaciones
Se puede considerar un TDA como una estructura que tiene una serie de op-
eraciones. Como estructura, los tipos abstractos de datos permiten agrupar
varios datos que mantengan alg un tipo de relacion aunque sean de distinto
tipo. Si se tienen los conjuntos A
1
, A
2
, A
3
, ..., A
n
, que denen diferentes tipos
de datos se puede denir el TDA A dado el producto cartesiano como A =
A
1
A
2
A
3
... A
n
.
Las operaciones que se pueden denir sobre un tipo de datos son las con-
structoras, las analizadoras, las modicadoras, las liberadoras, y otras funciones
de utilidad que se requieran en un TDA.
Funciones constructoras: Las funciones constructoras permiten como su nom-
bre lo indica construir la estructura del TDA dado. Debe tenerse en cuenta
que las variables no estan denidas. Para el caso de los enteros si se desea
denir una variable como entera x Z la equivalencia de dicha expresion
en un lenguaje de programacion como C++ sera int x. Si se tratase de
un arreglo de tipo entero x Z

, su denicion en C++ sera la encar-


gada de crear la variable como int* x. Los tipos primitivos de datos no
necesitan ser construidos en memoria pero en el caso de TDA dinamicos
denidos por un programador en lenguaje C++ se requiere una asignacion
en la memoria con el operador new.
Funciones Modicadoras: Estas funciones permiten cambiar un dato de un
TDA, estan relacionadas con las asignaciones.
Funciones Analizadoras: Estas funciones permiten obtener un dato miembro
de un TDA.
Funciones Liberadoras: Estas funciones permiten devolver la memoria em-
pleada por un TDA al sistema operativo. Los tipos de datos primitivos
no requieren esta denicion pero tipos de datos como los arreglos o los
TDA escritos por un programador deben ser liberados. Estan asociadas
al operador delete en C++.
1
Funciones de persistencia: Son funciones que permiten mantener el dato a
traves del tiempo. En este caso se han utilizado los ujos de datos para
leer o escribir los datos en archivos o enviarlos a la salida estandar de la
consola.
3 Denici on de un TDA
Para denir un TDA, llamado A partiendo de la denicion de producto carte-
siano A = A
1
A
2
A
3
... A
n
La denicion de dicho TDA en C++ sera la
siguiente:
struct base A{
A 1 a 1 ;
A 2 a 2 ;
A 3 a 3 ;
.
.
.
A n a n ;
};
typedef base A A;
La palabra struct declara la construccion de la estructura como el producto
cartesiano y typedef nos permite nombrar un puntero a la estructura base A
y as poder manipular el TDA como parametro en una funcion o retornarlo
como salida de funciones sin realizar cambios adicionales utilizando memoria
dinamica.
Como ejemplo pueden denirse los numeros complejos C como un TDA
constituido por dos numeros reales, uno que representa la parte real del y otro
que representa la parte imaginaria. C = R R. En C++ se declararan as:
struct bas e compl ej o {
double x ; // par t e r e al
double y ; // par t e i magi nari a
};
typedef bas e compl ej o compl ej o ;
3.1 Funciones Constructoras
Para construir un TDA se dene la operacion crear, que va matematicamente
de la declaracion del producto cartesiano y retornara la estructura. En general
se tiene:
crear A : A
1
A
2
A
3
... A
n
A
(a
1
, a
2
, a
3
, ..., a
n
) (a
1
, a
2
, a
3
, ..., a
n
)
En C++:
2
A crear A ( A 1 a 1 , A 2 a 2 , A 3 a 3 , . . . , A n a n ){
A a = new base A ;
a>a 1 = a 1 ;
a>a 2 = a 2 ;
a>a 3 = a 3 ;
.
.
.
a>a n = a n ;
return a ;
};
Si A
i

i=1,2,3,...,n
, es un tipo de datos no primitivo se aprovecha esta denicion
para llamar la funcion creadora del tipo A
i
dado con el parametro x
i
respectivo.
Para el caso de los n umeros complejos, la funcion creadora de complejo esta
denida matematicamente como:
crear complejo : R R C
(x, y) (x, y)
En C++:
compl ej o c r e ar c ompl e j o ( double x , double y){
compl ej o z = new bas e compl ej o ;
z>x = x ; // par t e r e al
z>y = y ; // par t e i magi nari a
return z ;
};
Para obtener un elemento miembro de la estructura se emplea el operador
->.
3.2 Funciones Analizadoras
Las funciones analizadoras permiten obtener un miembro de una estructura,
si se dene la estructura de un TDA como un producto cartesiano, la funcion
analizadora devolvera la proyeccion i-esima (notada
i
). Matematicamente las
funciones analizadoras se denen as:

i
: A A
i
(a
1
, a
2
, a
3
, ..., a
n
) a
i
En C++:
A i pa r t e i (A a ){
return a>a i ;
};
Una funcion analizadora para un numero complejo es la obtencion de la parte
real del numero:

1
: C R
(x, y) x
3
Para la parte imaginaria del n umero:

2
: C R
(x, y) y
En C++:
double pa r t e r e a l ( compl ej o z ){
return z>x ;
};
double par t e i magi nar i a ( compl ej o z ){
return z>y ;
};
3.3 Funciones Modicadoras
Estan asociadas a las asignaciones de un tipo de dato que hace parte de la es-
tructura del TDA y su funcion es inyectar un dato en la estructura reemplazando
el valor de un determinado tipo de dato.
En general se tiene la inyeccion i
k
del miembro de la estructura k como:
i
k
: A A
k
A
((a
1
, a
2
, a
3
, ..., a
n
), b) c|c
j
= a
j

j=1,2,3,...,nj=k
c
k
= b
Para el TDA complejo se tienen dos inyecciones, uno para la parte real:
i
1
: C R C
((x, y), r) (r, y)
Y otra para la parte imaginaria:
i
2
: C R C
((x, y), r) (x, r)
En C++:
compl ej o mo di f i c a r pa r t e r e a l ( compl ej o z , double x){
z>x = x ;
return z ;
};
compl ej o modi f i c ar par t e i magi nar i a ( compl ej o z , double y){
z>y = y ;
return z ;
};
4 Otras Funciones y Funciones Analizadoras
Constituyen cualquier funcion que se requiera sobre el tipo de dato dado. En
el caso de los numeros complejos la suma de dos n umeros complejos se dene
4
como otro numero complejo cuya parte real es la suma de las partes reales y
cuya parte imaginaria es la suma de las partes imaginarias.
sumar complejo : C C C
((x, y), (v, w)) (x + v, y + w)
En C++ se tiene:
compl ej o sumar compl ej o ( compl ej o z1 , compl ej o z2 ){
return c r e ar c ompl e j o ( z1>x + z2>x , z1>y + z2>y ) ;
};
5 Funciones de Persistencia o E/S
Las funciones de persistencia o de entrada y salida estan basadas en los conceptos
de ujos de datos.
Para leer un TDA de un ujo de datos debe leerse cada uno de los compo-
nentes de la estructura:
leer A : IS A
(is) (leer A
1
(is), leer A
2
(is), leer A
3
(is), ..., leer A
n
(is))
En C++:
A l e e r A ( i s t r eam& i s ){
return crear A ( l eer A1 ( i s ) , l eer A2 ( i s ) ,
l eer A3 ( i s ) , . . . , l eer An ( i s ) ) ;
};
Para el TDA que dene los n umeros complejos se tiene:
leer complejo : IS C
(is) (leer real(is), leer real(is))
En C++ se tiene, se hace una peque na variacion de la funcion leer complejo
con respecto a la notacion matematica pues al enviar funciones como parametros
en algunos casos suele llamarse primero la lectura de la parte imaginaria y luego
la de la parte real (los argumentos de funcion se procesan de derecha a izquierda
en algunas versiones de C++). Se modica la funcion con respecto a su notacion
matematica para leer primero la parte real y luego la imaginaria:
double l e e r r e a l ( i s t r eam& i s ){
double i ;
i s >> i ;
return i ;
};
compl ej o l e e r c ompl e j o ( i s t r eam& i s ){
double r e a l = l e e r r e a l ( i s ) ;
double im = l e e r r e a l ( i s ) ;
return c r e ar c ompl e j o ( r eal , im ) ;
};
5
Para escribir un TDA, debe escribirse cada uno de los componentes de la
estructura en el ujo de datos y retornar el ujo de datos. Se puede denir esta
funcion matematicamente aprovechando la composicion de funciones:
escribir A : OS A OS
(os, a) escribir A
n
(escribir A
n1
(...(escribir A
1
(os, a
1
), ...)a
n1
), a
n
)
En C++:
ostream& e s c r i bi r A ( ostream& os , A a ){
return e s c r i bi r An ( . . . ( e s c r i bi r A2 ( e s c r i bi r A 1 ( os , a 1 ) ,
a2 ) , . . . ) , a n ) ;
};
Para la escritura de un n umero complejo en un ujo se tiene:
escribir complejo : OS C OS
(os, z) (escribir real(escribir real(os, x), y)
En C++ (se agrega el codigo de escribir real por comodidad):
ostream& e s c r i b i r r e a l ( ostream& os , double x){
os << x << \ t ;
};
ostream& e s c r i bi r c o mpl e j o ( ostream& os , compl ej o z ){
return e s c r i b i r r e a l ( e s c r i b i r r e a l ( os , z>x ) , z>y ) ;
};
Debe tenerse en cuenta que para mejorar la escritura del tipo de dato la
funcion escribir real que se denio en la parte de ujos de datos escribe un
caracter tabulador al nal de cada dato. La declaracion de esta funcion equivale
a:
ostream& e s c r i bi r c o mpl e j o ( ostream& os , compl ej o z ){
return os << x << \ t << y << \ t ;
};
6 Funciones Liberadoras
Las funciones liberadoras devuelven la memoria empleada por la estructura del
TDA al sistema operativo. En este caso si un tipo de dato A
i
es primitivo
no requiere liberacion si no es primitivo debera liberarse antes de liberarse la
estructura.
En general se tiene:
liberar A : A
(a)
En C++ se tiene:
6
void l i be r ar A (A a ){
l i be r ar A1 ( a>a1 ) ;
l i be r ar A2 ( a>a2 ) ;
l i be r ar A3 ( a>a3 ) ;
.
.
l i be r ar An ( a>an ) ;
de l e t e a ;
};
Para el caso de los n umeros complejos, se tiene la siguiente funcion liber-
adora:
liberar complejo : C
(z)
Como el tipo real (double) es primitivo, lo unico que se debe liberar es la
estructura. En C++ se tiene:
void l i be r ar c o mpl e j o ( compl ej o z ){
de l e t e z ;
};
7 Programa Principal
Tomando la denicion de TDA de complejo un sencillo programa que lee dos
complejos de la entrada estandar de consola cin e imprime en la salida estandar
cout es:
i nt main ( ) {
compl ej o z1 = l e e r c ompl e j o ( ci n ) ;
compl ej o z2 = l e e r c ompl e j o ( ci n ) ;
compl ej o z3 = sumar compl ej o ( z1 , z2 ) ;
e s c r i bi r c o mpl e j o ( cout , z3 ) ;
l i be r ar c o mpl e j o ( z1 ) ;
l i be r ar c o mpl e j o ( z2 ) ;
l i be r ar c o mpl e j o ( z3 ) ;
system( pause ) ;
return 0;
};
Dado el siguiente ujo de entrada de consola dado por un usuario corre-
spondiente a la suma de dos complejos (3, 4i) y (2, 5i), el programa retorna
a la salida de consola la suma de dos complejos (1, 1i) como se aprecia a
continuacion:
-3 4
2 -5
-1 -1 Press any key to continue . . .
Debe observarse que toda estructura creada despues de utilizarse es liberada
en el programa principal.
7
8 TDA Estudiante
Se puede denir un TDA llamado estudiante, cuya estructura es:
nombre ASCII

apellido ASCII

unas notas (por comodidad hemos denido 5 notas): notas R


5
Un estudiante se dene como E = ASCII

ASCII

R
5
En C++ se tiene:
/
Es t ruct ura bas i ca de dat os que s oport a un e s t udi ant e
con nombre , a p e l l i d o y 5 not as r e a l e s
/
struct bas e e s t udi ant e {
char nombre ;
char a pe l l i do ;
double notas ;
};
/
Const ant e que r epr es ent a e l numero de not as de un
e s t udi ant e
/
#define NUMERONOTAS 5
/
El verdadero e s t udi ant e es un apuntador a l a
e s t r uc t ur a base nos permi t e us ar l o de manera
dinamica
/
typedef bas e e s t udi ant e e s t udi ant e ;
Dada esta estructura del TDA estudiante lo que resta denir son sus fun-
ciones:
Funcion creadora de Estudiante: La funcion creadora de estudiante se de-
ne como aquella que recibe dos cadenas de caracteres correspondientes
al nombre y al apellido y las 5 notas y crea la estructura estudiante.
crear estudiante : ASCII

ASCII

R R R R R E
(nombre, apellido, nota1, nota2, nota3, nota4, nota5)
(nombre, apellido, notas)|notas
i
= nota
i
i = 1, 2, .., 5)
En C++ primero se debe crear el apuntador a la estructura base y luego
crear las cadenas de caracteres y el arreglo de tipo real. Dado que estas
funciones se encuentran en otros captulos, se llaman directamente las
funciones:
8
e s t udi ant e c r e a r e s t udi a nt e ( char nombre , char ape l l i do ,
double n1 , double n2 , double n3 , double n4 , double n5 ){
e s t udi ant e E = new bas e e s t udi ant e ;
E>nombre = copi ar cadena ( nombre ) ;
E>a pe l l i do = copi ar cadena ( a pe l l i do ) ;
E>notas = c r e a r a r r e g l o r e a l (NUMERONOTAS) ;
E>notas [ 0 ] = n1 ;
E>notas [ 1 ] = n2 ;
E>notas [ 2 ] = n3 ;
E>notas [ 3 ] = n4 ;
E>notas [ 4 ] = n5 ;
return E;
};
Funciones analizadoras de estudiante: Se tienen tres funciones analizado-
ras de estudiante. Una para el nombre, otra para el apellido y otra para
las notas.

1
: E ASCII

(nombre, apellido, notas) nombre

2
: E ASCII

(nombre, apellido, notas) apellido

3
: E R

(nombre, apellido, notas) notas


En C++ se tiene:
char obtener nombre ( e s t udi ant e E){
return E>nombre ;
};
char o bt e ne r a pe l l i do ( e s t udi ant e E){
return E>a pe l l i do ;
};
double obt ener not as ( e s t udi ant e E){
return E>notas ;
};
Funciones modicadoras o asignaciones: Para el TDA estudiante se tienen
tres funciones inyectoras para el nombre, el apellido y las notas, respecti-
vamente.
i
1
: E ASCII

E
(e, n) e

|nombre(e

) = n apellido(e

) = apellido(e) notas(e

) =
notas(e)
i
2
: E ASCII

E
(e, a) e

|nombre(e

) = nombre(e) apellido(e

) = a notas(e

) =
9
notas(e)
i
3
: E R

E
(e, nt) e

|nombre(e

) = nombre(e) apellido(e

) = apellido(e)
notas(e

) = nt
Para la traduccion en C++ se requiere tener la implementacion, de la
funcion que copia una cadena y un arreglo de double, en este caso como la
funcion de copia genera una nueva cadena, es necesario liberar cada parte
de la estructura:
e s t udi ant e f i j ar nombr e ( e s t udi ant e E, char s t r ){
l i be r ar c ade na (E>nombre ) ;
E>nombre = copi ar cadena ( s t r ) ;
return E;
};
e s t udi ant e f i j a r a p e l l i d o ( e s t udi ant e E, char s t r ){
l i be r ar c ade na (E>a pe l l i do ) ;
E>a pe l l i do = copi ar cadena ( s t r ) ;
return E;
};
e s t udi ant e f i j a r n o t a s ( e s t udi ant e E, double notas ){
l i be r a r a r r e g l o do ubl e (E>notas ) ;
E>notas = c o pi a r a r r e g l o doubl e (E>notas , NUMERONOTAS) ;
return E;
};
Funciones de entrada y salida Para leer un estudiante, se debe leer el nom-
bre y el apellido que son cadenas y posteriormente se debe leer el arreglo
de un ujo de datos.
leer estudiante : IS E
(is) (leer cadena(is), leer cadena(is), leer arreglo real(is))
En C++ se tiene:
e s t udi ant e l e e r e s t udi a nt e ( i s t r eam& i s ){
char nombre = cr ear cadena ( 3 0 ) ;
nombre = l e e r c ade na ( i s , nombre , 30) ;
char a pe l l i do = cr ear cadena ( 3 0 ) ;
a pe l l i do = l e e r c ade na ( i s , ape l l i do , 30) ;
double notas = c r e a r a r r e g l o r e a l ( 5 ) ;
notas = l e e r a r r e g l o r e a l ( i s , notas , NUMERONOTAS) ;
e s t udi ant e E = c r e a r e s t udi a nt e ( nombre , ape l l i do , notas [ 0 ] ,
notas [ 1 ] , notas [ 2 ] , notas [ 3 ] , notas [ 4 ] ) ;
l i be r ar c ade na ( nombre ) ;
l i be r ar c ade na ( a pe l l i do ) ;
l i b e r a r a r r e g l o r e a l ( notas ) ;
10
return E;
};
Para mostrar un estudiante en un ujo de datos, se llama a la funcion de
impresion de cada tipo de dato de la estructura:
escribir estudiante : OS E OS
(os, nombre, apellido, notas) escribir cadena(nombre) escribir cadena(nombre)
escribir arreglo double(notas)
ostream& e s c r i b i r e s t u d i a n t e ( ostream& os , e s t udi ant e E){
e s c r i bi r c a de na ( os , obtener nombre (E) ) ;
e s c r i bi r c a de na ( os , o bt e ne r a pe l l i do (E) ) ;
e s c r i b i r a r r e g l o r e a l ( os , obt ener not as (E) , NUMERONOTAS) ;
return os ;
};
Funciones liberadoras: Para liberar el TDA estudiante primero se libera
cada tipo de datos no primitivo y por ultimo se libera la estructura.
liberar estudiante :
(nombre, apellido, notas) liberar cadena(nombre) liberar cadena(apellido)
liberar arreglo double(notas(e))
En C++ se tiene:
void l i be r a r e s t udi a nt e ( e s t udi ant e E){
l i be r ar c ade na ( obtener nombre (E) ) ;
l i be r ar c ade na ( o bt e ne r a pe l l i do (E) ) ;
l i b e r a r a r r e g l o r e a l ( obt ener not as (E) ) ;
de l e t e E;
};
Otras funciones sobre estudiante: Una posible funcion puede ser la de cal-
cular el promedio de notas del estudiante.
promedio estudiante : E R
(nombre, apellido, notas)
1
5

5
i=1
notas
i
En C++ se tiene:
double promedi o ( e s t udi ant e E){
double acum = 0 . 0 ;
i nt i ;
for ( i = 0; i < NUMERONOTAS; i ++){
acum = acum + obt ener not as (E) [ i ] ;
};
return acum/NUMERONOTAS;
};
Un programa principal para el TDA que se ha denido podra ser como el
siguiente:
11
i nt main ( ) {
e s t udi ant e E = l e e r e s t udi a nt e ( ci n ) ;
cout << Estudi ante l e i do ;
e s c r i b i r e s t u d i a n t e ( cout , E) ;
cout << l a nota de << obtener nombre (E) << es << promedi o (E) ;
l i be r a r e s t udi a nt e (E) ;
system( pause ) ;
return 0;
};
12

Vous aimerez peut-être aussi