Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ESTRUCTURAS DE DATOS
OBJETIVOS
Definir un nuevo TDA utilizando las técnicas ya revisadas
Implementar TDAs usando un lenguaje de programación y
técnicas de modularización
Reconocer la utilidad de un tipo de dato Generico
Utilizar TDAs ya creados para resolver problemas
INTRODUCCION
Los tipos de datos básicos
Enteros, reales, caracteres, lógicos
Son también de alguna forma TDAs
Cuando se desea sumar dos enteros
No es necesario conocer la representación binaria de cada valor
entero
Solo debe conocerse el comportamiento que hace la suma: (+)
Básicamente 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
posición, 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 estática o dinámica, como se desee
Podemos declararlos. Ejemplo:
int A[20] o int *A;
Y modificar y consultar los elementos. Ejemplo:
A[5] = 4 o printf(“%d”, A[5])
Si el TDA Arreglo en C ya provee el
comportamiento necesario
¿Por que crear otro tipo de dato que lo sustituya?
LOS PROBLEMAS
Características negativas de un arreglo en C
Si es un arreglo estático,
El tamaño real debe ser determinado desde el inicio, lo cual es muy molestoso
Si es un arreglo dinámico
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 tamaño del arreglo no es parte del arreglo
etc.…
Existen demasiadas características de los arreglos
Que añaden complejidad al manejo de arreglos
Recordemos la abstracción: quitar complejidad, dejar solo lo necesario
UN NUEVO TDA: ARRAYU
Una abstracción “arreglaría” estos detalles
Crearíamos un nuevo tipo de dato que
Solo muestre lo que se necesita y esconda la complejidad
Podríamos crear el nuevo TDA para arreglos
unitarios
ArrayU
DISEÑO DEL TDA: NIVEL
LOGICO
El diseño de un TDA implica
Determinar el comportamiento del mismo: operaciones
Determinar la definición interna del mismo:
características
Este diseño también se puede llamar
Nivel lógico del TDA
Pensemos en el nivel lógico para
Nuestro nuevo arreglo: ArrayU
ArrayU: COMPORTAMIENTO
Existen dos niveles de comportamiento:
Básico: sin el cual no se puede trabajar con el TDA
Complementario: operaciones que facilitan el manejo del TDA
Comportamiento básico: A un ArrayU se debe poder
Crearlo, de cualquier tamaño
Destruirlo
Asignar un valor a uno de sus elementos
Consultar el valor de uno de sus elementos
Consultar el tamaño máximo del arreglo
Comportamiento complementario
Ordenarlo
Buscar un elemento dado su valor, etc.
ArrayU: ESTADO
Primero es útil pensar la definición de nuestro TDA
Un arreglo es
Una colección de elementos finita y de tamaño 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 + tamaño -1
Estudiante_Imprimir(E);
Estudiante_Imprimir(E);
break;
break;
case QUEBRADO:
case QUEBRADO:
QQ == A->Elementos[i];
A->Elementos[i];
Quebrado_Imprimir(Q);
Quebrado_Imprimir(Q);
DESVENTAJAS
Son obvias:
Esta función no sirve para cualquier tipo de dato
Para que ArrayU soporte un nuevo tipo de dato hay que
modificar la función
Buscar al creador del TDA
Pedirle que añada un case para el nuevo tipo de dato
Pedirle que recompile la librería
Pedirle el nuevo .h y el nuevo .lib
MUCHO TRABAJO!!
Esta solución no favorece la expandibilidad del TDA
SEGUNDA SOLUCIÓN
Implementar la función 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
Sería una acción una función, como parametro
void
void ArrayU_Imprimir(ArrayU
ArrayU_Imprimir(ArrayU *A,
*A, procfn
procfn Imprimir){
Imprimir){
for(i = 0; i< A->tmax; i++){
for(i = 0; i< A->tmax; i++){
//Imprimir
//Imprimir A->Elementos[i],
A->Elementos[i], NONO SE
SE COMO
COMO
HACERLO
HACERLO
//Llamo
//Llamo aa la
la funcion
funcion Imprimir
Imprimir recibida
recibida
como parametro
como parametro
Imprimir(A->Elementos[i]);
Imprimir(A->Elementos[i]);
}}
}}
void
void ImprimirEntero(int
ImprimirEntero(int *valor);
*valor);
void
void ImprimirCadena(char *cadena);
ImprimirCadena(char *cadena);
void
void Estudiante_Imprimir(Estudiante *E);
Estudiante_Imprimir(Estudiante *E);
void Quebrado_Imprimir(Quebrado *Q);
void Quebrado_Imprimir(Quebrado *Q);
main(){
main(){
ArrayU
ArrayU *A;
*A;
AA == ArrayU_Crear(10);
ArrayU_Crear(10);
//Se
//Se piden
piden 10
10 Estudiante
Estudiante por
por teclado
teclado
//y se almacenan en
//y se almacenan en A A
ArrayU_Imprimir(A,
ArrayU_Imprimir(A, Estudiante_Imprimir);
Estudiante_Imprimir);
}}
FUNCIONES CALLBACKS
Es una herramientas de programación que nos ofrece
lenguaje C
Permite crear un tipo de dato que describa una función
En forma muy genérica
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 función que coincida con este prototipo
Puede decirse que pertenece al nuevo tipo de dato declarado
EJEMPLO: LA GRAPHAPP
El prototipo de la función que crea un nuevo botón es:
button newbutton(char *text, rect r, actionfn fn);
Recibe un texto, un rectángulo y al parecer una variable de tipo
actionfn
Actionfn debe ser un nuevo tipo de dato, su declaración es:
typedef void (*actionfn)(button b);
Esto indica que cualquier función 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
Volviendo a nuestro caso,
La función callback que necesitamos cumplirá la tarea de imprimir
un dato Generico:
typedef void (*Generico_Imprimir)(Generico);
Cualquier función 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 función para imprimir un ArrayU quedaría entonces
void ArrayU_Imprimir(ArrayU *A, Generico_Imprimir fn);