Está en la página 1de 42

TDA ARRAYU

ESTRUCTURAS DE DATOS

OBJETIVOS

Definir un nuevo TDA utilizando las tcnicas ya revisadas


Implementar TDAs usando un lenguaje de programacin y tcnicas de modularizacin

Reconocer la utilidad de un tipo de dato Generico Utilizar TDAs ya creados para resolver problemas

INTRODUCCION

Los tipos de datos bsicos

Enteros, reales, caracteres, lgicos Cuando se desea sumar dos enteros No es necesario conocer la representacin binaria de cada valor entero Solo debe conocerse el comportamiento que hace la suma: (+)

Son tambin de alguna forma TDAs


Bsicamente todos los tipos de datos se pueden considerar TDAs

Qu ES UN ARREGLO?

El arreglo es un tipo de dato compuesto Permite agrupar elementos del mismo tipo Permite acceder a CADA elementos utilizando su posicin, recordemos que se puede
Consultar el valor de un elemento Modificar el valor de un elemento

Lenguaje C si nos permite trabajar con arreglos

ARREGLOS EN C

C ya provee de una forma de trabajo con arreglos


En forma esttica o dinmica, como se desee Podemos declararlos. Ejemplo:

int A[20] o int *A; A[5] = 4 o printf(%d, A[5])

Y modificar y consultar los elementos. Ejemplo:

Si el TDA Arreglo en C ya provee el comportamiento necesario

Por que crear otro tipo de dato que lo sustituya?

LOS PROBLEMAS

Caractersticas negativas de un arreglo en C


Si es un arreglo esttico,

El tamao real debe ser determinado desde el inicio, lo cual es muy molestoso

Si es un arreglo dinmico

El uso de malloc para crearlo abarca una cierta complejidad que podriamos ocultar

Puedo intentar asignar valores a elementos fuera del rango del arreglo Los ndices siempre comienzan desde 0 y eso no se puede cambiar El tamao del arreglo no es parte del arreglo etc. Que aaden complejidad al manejo de arreglos Recordemos la abstraccin: quitar complejidad, dejar solo lo necesario

Existen demasiadas caractersticas de los arreglos

UN NUEVO TDA: ARRAYU

Una abstraccin arreglara estos detalles

Crearamos un nuevo tipo de dato que

Solo muestre lo que se necesita y esconda la complejidad

Podramos crear el nuevo TDA para arreglos unitarios


ArrayU

DISEO DEL TDA: NIVEL LOGICO

El diseo de un TDA implica


Determinar el comportamiento del mismo: operaciones Determinar la definicin interna del mismo: caractersticas

Este diseo tambin se puede llamar

Nivel lgico del TDA Nuestro nuevo arreglo: ArrayU

Pensemos en el nivel lgico para

ArrayU: COMPORTAMIENTO

Existen dos niveles de comportamiento:

Bsico: sin el cual no se puede trabajar con el TDA Complementario: operaciones que facilitan el manejo del TDA
Crearlo, de cualquier tamao Destruirlo Asignar un valor a uno de sus elementos Consultar el valor de uno de sus elementos Consultar el tamao mximo del arreglo Ordenarlo Buscar un elemento dado su valor, etc.

Comportamiento bsico: A un ArrayU se debe poder

Comportamiento complementario

ArrayU: ESTADO

Primero es til pensar la definicin de nuestro TDA Un arreglo es

Una coleccin de elementos finita y de tamao fijo.


A cada elemento se lo puede acceder por un ndice

El ndice del primer elemento puede comenzar desde un numero dado El ndice del ultimo elemento seria igual a: indice_primero + tamao -1
::= {<elemento><inicial>, ... , <elemento><iterador>, <elemento><final>}

<arreglo>

<iterador> ::= (<inicial>|<inicial>+1|<inicial>+2|...|<final>)

<inicial>
<final> <nreal>

::= <entero_positivo>
::= <inicial>+<nreal>-1 ::= <digito>{<digito>}

<elemento> ::= <dato>{<dato>}

TDAs: NIVEL DE IMPLEMENTACION

Una vez completo el nivel lgico,


Podemos pasar al nivel de implementacin Usando un lenguaje de programacin determinado Estndar para nombrar TDAs y operaciones

Hay algunas consideraciones que tomar

Es preferible crear un estndar til para todos los TDAs que se vayan a crear Ejemplo: <nombre_TDA>_<nombre_funcion> o <nombre_funcion><nombre_TDA>

Uso de modularidad a nivel de archivo

MODULARIZACION DE ARCHIVOS

En la programacin estructurada, los TDAs se implementan en mdulos Un modulo normalmente esta compuesto por:

Interfaz o especificacin, en lenguaje C, se refiere a los archivos .h:

Contienen la declaracin del nuevo tipo y Los prototipos de las operaciones que estarn disponibles

Implementacin, en lenguaje C, se refiere a los archivos .c


Contendr el cdigo fuente de cada operacin Cada implementacin o forma de llevarse a cabo de las operaciones, estarn ocultas para el mundo exterior

En resumen, un TDA bien modularizado a nivel de archivo, ocupar

Dos archivos, un .h y un .c, con el nombre del TDA

ARRAYU: NIVEL DE IMPLEMENTACION

Crear
Dado un tamao, ArrayU almacenara una arreglo de dicho tamao ArrayU *ArrayU_Crear (int tamanio, int inicial);

Eliminar
Dado un arreglo, se eliminara de memoria void ArrayU_Eliminar(ArrayU **A);

Consultar
int ArrayU_ GetElemento(ArrayU *A, int indice); Int ArrayU_GetTam(ArrayU *A); int ArrayU_GetInicial(ArrayU *A); Int ArrayU_GetFinal(ArrayU *A);

Modificar void ArrayU_SetElemento(ArrayU *A, int indice, int valor);

ARRAYU: NIVEL DE IMPLEMENTACION

Consideraciones

Un arreglo es el conjunto de elementos Con un tamao dado y un numero de ndice inicial

Declaracin:
OJO: ArrayU solo servir para arreglos de enteros

typedef struct{ int *Arreglo; int nreal; int inicial; }ArrayU;

ARRAYU: NIVEL DE APLICACION


Ahora que hemos construido nuestro nuevo TDA

Podemos usarlo en un programa Pedir n elementos por teclado, almacenarlos en un arreglo y luego mostrar la mitad de cada valor ingresado Usemos nuestra propia abstraccin

Veamos un ejemplo de esto en el siguiente ejercicio

No usaremos mas los arreglos que conocamos

LEER, CAMBIAR E IMPRIMIR


main(){ ArrayU *Datos; int n, valor; printf(Cuntos datos maximo desea ingresar?); n = GetInteger(); Datos = ArrayU_Crear(n,1); for(i = ArrayU_GetInicio(*Datos); i <= ArrayU_GetFinal(*Datos);i++){ //Inicio i en el for desde 1, no desde 0 printf(Ingrese el dato No., i); valor = GetInteger(); ArrayU_SetElemento(Datos,i, valor); //Pido el elemento i } for(i = ArrayU_GetInicio(*Datos); i <= ArrayU_GetFinal(*Datos);i++){ valor = ArrayU_GetElemento(*Datos,i)/2; ArrayU_SetElemento(Datos, i, valor); printf(Mitad del elemento %d: , valor); } ArrayU_Eliminar(&Datos); }

SOLO PARA ENTEROS


ArrayU ha sido un xito, pero


Lo implementamos solo para enteros Crear un TDA para cada tipo de dato
ArrayUI, solo para enteros, ArrayUF, para reales ArrayUS, para strings, etc.

Dos posibles soluciones

Crear un tipo de dato sper general: Generico

Modificar ArrayU para que sea un arreglo de cualquier tipo de dato un arreglo de genericos

TIPO DE DATO GENERICO

Cualquier TDA que represente un conjuntos de datos, tendr este problema


De que tipo son esos elementos? Si lo definimos de un tipo especifico, nuestro TDA quedar muy limitado Abstraernos y crear un Tipo de Dato Generico Este nuevo TDA permitir representar cualquier tipo de dato, sea un entero, un real, u otro TDA

Qu podemos hacer?

Y COMO SE COMPORTARIA UN GENERICO?


La idea es lograr almacenar cualquier tipo de dato dentro de una variable de tipo Generico
Una variable de tipo generico se puede crear

g 4

g 6

Pero al hacerlo, habr que especificar memoria para que tipo de dato exactamente Esto depender del tipo del valor que va a almacenar

Tambin se le puede cambiar o consultar el valor que almacena


Generico g; g = CrearEntero(4); CambiarEntero(g, 6); g = CrearCadena(Mama); CambiarCadena(g, Papa);

g Mama

g
Papa

GENERICO: NIVEL LOGICO

Un tipo de dato Generico, debe permitir

Crear un Generico, escondiendo un valor que cualquier tipo


Generico g; g = CrearEntero(4);

Eliminar una variable de tipo Generico Modificar el valor escondido, Ej. Con enteros

Consultar y Modificar el valor escondido dentro


SetEntero(G,5); valor = GetEntero(g);

Consultar el valor que el Generico almacena, Ej. Con Enteros

GENERICO: NIVEL LOGICO

Qu representa el Generico?

A cualquier tipo de dato, ya sea bsico como compuesto


<generico> ::= <dato> <dato> ::= <bsico>|<compuesto> <bsico> ::= <int>|<float>|<double>|<char>|<string> <compuesto>::= <arreglo>|<estructura>|<union>|<user_defined>

Es decir

GENERICO: NIVEL DE IMPLEMENTACION

Que un valor sea Generico implica que


No debe ser de ningn tipo al ser declarado Y dependiendo de quien lo use, En algn momento se convertira al tipo deseado Reserva de memoria dinmica y Conversin explicita de un tipo a otro

Esto implicara

En lenguaje C

El nico tipo de dato que no es NADA es el void


Una variable Generico, seria realmente de tipo: void *

Entonces

Que al inicio no es de ningn tipo

void * puede apuntar a cualquier tipo de variable

GENERICO: NIVEL DE IMPLEMENTACION

Operaciones

Creacin

Generico Generico_CrearEntero(int valor); Generico_Eliminar(Generico g); void Generico_AsignarEntero(Generico g, int valor); int Generico_ObtenerEntero(Generico g);

Eliminar

Modificar y Consultar

Declaracin

typedef void * Generico ;

GENERICO: EN C

1007

72 5 Generico g; g = Generico_CrearInt(5); G Generico_SetInt(g,Generico_GetInt(g)+67); 2056 printf(%d\n, Generico_GetInt(g)); Mama y Papa Mama Generico_Eliminar(g); g = Generico_CrearString(Mama); 1343 strcpy(cad,Generico_GetString(g)); strcat(cad, y Papa); Mama y Papa Mama Generico_SetString(g, cad); printf(%d\n, Generico_GetString(g)); Generico_Eliminar(g);

GENERICO: NIVEL DE APLICACION

Bien utilizado

El tipo de dato Generico puede ser sumamente til A lo largo de todo el curso Nunca olvidar que las conversiones sern necesarias Si las dejamos a un lado, el resultado ser no esperado ni deseado

Para usarlo hay que considerar


REDEFINICION DE ARRAYU

Necesitamos redeclarar el TDA ArrayU


Para definirlo como un arreglo de cualquier tipo de dato OJO: la definicin en el nivel lgico sigue igual Solo cambiara el nivel de implementacin

typedef struct{ Generico *Arreglo; int nreal; int inicial; }ArrayU;

ARRAYU GENERICO: NIVEL DE APLICACION

Tratemos ahora de usar el ArrayU Generico


Apliqumoslo en el mismo ejemplo anterior:

Pedir n elementos por teclado, almacenarlos en un arreglo y luego mostrar la mitad de cada valor ingresado

main(){ ArrayU *Datos; int n, valor; Generico g; printf(Cuntos datos maximo desea ingresar?); n = GetInteger(); Datos = ArrayU_Crear(n,1); for(i = ArrayU_GetInicio(Datos); i <=ArrayU_GetFinal(Datos);i++){ //Inicio i en el for desde 1, no desde 0 printf(Ingrese el dato No., i); valor = GetInteger(); g = Generico_CrearEntero(valor); ArrayU_SetElemento(Datos,i, g); //Pido el elemento i } for(i = 1; i <= Datos.n ; i++){ g = ArrayU_GetElemento(Datos,i); valor= Generico_GetEntero(g)/2; Generico_SetEntero(g, valor); printf(Mitad del elemento %d: , Generico_GetEntero(g)); } ArrayU_Eliminar(&Datos); }

VENTAJAS Y DESVENTAJAS

Ventajas

Logramos definir un arreglo mas funcional


Siempre tiene consigo su tamao, su ndice inicial y Sirve para cualquier tipo de dato

Ocultamos todos los detalles.. la verdad, detrs de la abstraccin

Desventajas
Como estamos muy acostumbrados al arreglo normal Este parece poco necesario

ARRAYU: AADIR MAS COMPORTAMIENTO

Podramos en algunos caso,

Desear que se imprima todo el arreglo por pantalla

Pero habra un problema para implementar esta herramienta

Considerando que nuestro arreglo es Generico

Qu problema/s podran surgir al tratar de hacer esta herramienta?

LO QUE DESEAMOS

Una herramienta que imprima un arreglo

Que no le importe el tipo

Analicemos que necesita esta funcin para cumplir bien su propsito


Necesitara el arreglo, para poder imprimirlo y Pero como sabra como imprimir cada elemento???

Cada elemento es Generico, ArrayU no conoce el tipo de dicho Generico, y por lo tanto, no puede imprimirlo Un ArrayU, que es el que se desea imprimir Y algo que le indique como imprimir cada elemento del arreglo Pues desde dentro del TDA se desconoce como hacerlo

La funcin debera recibir :


UNA PRIMERA SOLUCIN

Que la funcin reciba una enumeracion que indique de que tipo es el ArrayU
void ArrayU_Imprimir(ArrayU *A, TipoDato tipo); En ese caso, la funcin debera elegir como imprimir el arreglo, dependiendo del tipo:

void ArrayU_Imprimir(ArrayU *A, TipoDato tipo){ for(i = 0; i< A->tmax; i++){ switch(tipo){ int *valor_int; char *cadena; Estudiante *E; Quebrado *Q; case ENTERO: valor_int = A>Elementos[i]; printf(%d\n, *valor_int); break; case CADENA: cadena = A>Elementos[i]; printf(%s\n, cadena); break; case ESTUDIANTE: E = A->Elementos[i]; Estudiante_Imprimir(E); break; case QUEBRADO: Q = A->Elementos[i]; Quebrado_Imprimir(Q);

DESVENTAJAS

Son obvias:
Esta funcin no sirve para cualquier tipo de dato Para que ArrayU soporte un nuevo tipo de dato hay que modificar la funcin

Buscar al creador del TDA Pedirle que aada un case para el nuevo tipo de dato Pedirle que recompile la librera Pedirle el nuevo .h y el nuevo .lib

MUCHO TRABAJO!!

Esta solucin no favorece la expandibilidad del TDA

SEGUNDA SOLUCIN

Implementar la funcin igual que si conociera el tipo de dato

Enfocarnos en el algoritmo, no en el tipo de dato

Pero.. Aquello que no sepamos como hacer


Porque desconocemos el tipo de dato Lo debemos recibir como parametro

Y no seria un valor Sera una accin una funcin, como parametro

void ArrayU_Imprimir(ArrayU *A, procfn Imprimir){ for(i = 0; i< A->tmax; i++){ //Imprimir A->Elementos[i], NO SE COMO HACERLO //Llamo a la funcion Imprimir recibida como parametro Imprimir(A->Elementos[i]); }
} void void void void ImprimirEntero(int *valor); ImprimirCadena(char *cadena); Estudiante_Imprimir(Estudiante *E); Quebrado_Imprimir(Quebrado *Q);

main(){

ArrayU *A; A = ArrayU_Crear(10); //Se piden 10 Estudiante por teclado //y se almacenan en A ArrayU_Imprimir(A, Estudiante_Imprimir);
}

FUNCIONES CALLBACKS
Es una herramientas de programacin que nos ofrece lenguaje C Permite crear un tipo de dato que describa una funcin

En forma muy genrica Se indica tipo de dato de retorno Se indica los tipos de datos de entrada Ejemplo:

typedef TipoRetorno (*Nombre_Nuevo_Tipo)(<valores de entrada>);

Cualquier funcin que coincida con este prototipo

Puede decirse que pertenece al nuevo tipo de dato declarado

EJEMPLO: LA GRAPHAPP

El prototipo de la funcin que crea un nuevo botn es:

button newbutton(char *text, rect r, actionfn fn);

Recibe un texto, un rectngulo y al parecer una variable de tipo actionfn Actionfn debe ser un nuevo tipo de dato, su declaracin es:

typedef void (*actionfn)(button b); Esto indica que cualquier funcin que coincida con el prototipo declarado para actionfn ser de tipo actionfn

Ejemplo:
void CalcularSalarios(button b); //. button b; b = newbutton(Aceptar, rect(10,10,10,10), CalcularSalarios);

SU UTILIDAD

Ese mecanismo nos va a permitir

Crear funciones que necesiten llamar a otras funciones La funcin callback que necesitamos cumplir la tarea de imprimir un dato Generico:

Volviendo a nuestro caso,

typedef void (*Generico_Imprimir)(Generico);

Cualquier funcin que tenga este prototipo caer en este tipo. Ejemplo:

void Imprimir_Entero(int *a); o void Imprimir_String(char *s);

USANDO UNA FUNCION COMO PARAMETRO

Nuestra funcin para imprimir un ArrayU quedara entonces

void ArrayU_Imprimir(ArrayU *A, Generico_Imprimir fn);

La implementacin de esta funcin quedara algo como:


void ArrayU_Imprimir(ArrayU *A, Generico_Imprimir fn){
int i; for(i = 0; i < A->nreal;i++){ fn(ArrayU_ElemC(A,i);); } }

LLAMANDO A LA IMPRESION
void Imprimir_Entero(int *valor); main(){ ArrayU *Datos; int n, valor; Generico g; printf(Cuntos datos maximo desea ingresar?); n = GetInteger(); Datos = ArrayU_Crear(n,1); for(i = ArrayU_Inicio(Datos); i <= ArrayU_Final(Datos) ;i++){ printf(Ingrese el dato No., i); valor = GetInteger(); g = Generico_CrearInt(valor/2); ArrayU_SetElementos(Datos,i,g); } ArrayU_Imprimir(Datos, Imprimir_Entero); ArrayU_Eliminar(&Datos); } void Imprimir_Entero(int *valor){ printf(%d, *valor); }

VENTAJAS DEL CALLBACK

Puedo definir funciones genericas

A travs de la definicin de tipos de datos de funciones

Son tiles cuando un procedimiento que se ejecutar es variable en el problema


Todos los procedimientos posibles de llamar Deben tener el prototipo en comn

También podría gustarte