You are on page 1of 9

c

c
cccc


 c


 c
c  c



c

c c
 c
c


 
c

  c 
c

c 
c

 c c  
c 
c


c c  
c c


c
c
c 
c




cc  c

c


 c

c
c 
 c 
c


c
c

 c

c
c
 

c
cc
c c  cc c
  c
c  c
 c
c  c   c

Un !"#c $%c $& #c &'( )&* # ( ) o !"#c &'( )&* #c $%c $& #( ( ) es un modelo matemático
compuesto por una colección de operaciones definidas sobre un conjunto de datos para el modelo.

La abstracción de datos consiste en ocultar las características de un objeto y obviarlas, de manera


que solamente utilizamos el nombre del objeto en nuestro programa.

Un TDA es representado por su interfaz, la cual sirve como cubierta a la correspondiente


implementación. Los usuarios de un TDA tienen que preocuparse por la interfaz, pero no con la
implementación, ya que esta puede cambiar en el tiempo y afectar a los programas que usan el
TDA. Esto se basa en el concepto de Ocultación de información, una protección para el programa
de decisiones de diseño que son objeto de cambio.

La solidez de un TDA reposa en la idea de que la implementación está escondida al usuario. Solo
la interfaz es pública. Esto significa que el TDA puede ser implementado de diferentes formas, pero
mientras se mantenga consistente con la interfaz, los programas que lo usan no se ven afectados.

La abstracción permite establecer un nivel jerárquico en el estudio de los fenómenos, el cual se


establece por niveles sucesivos de detalles. Generalmente, se sigue un sentido descendente de
detalles, desde los niveles más generales a los niveles más concretos.

Algunos ejemplos de utilización de TDAs en programación son:

ß #+,-+ #(: Implementación de conjuntos con sus operaciones básicas (unión, intersección
y diferencia), operaciones de inserción, borrado, búsqueda...
ß å)'#.%(c!+&)!#(c$%c/(0-%$&: Implementación de árboles de elementos, utilizados para
la representación interna de datos complejos. Aunque siempre se los toma como un TDA
separado son parte de la familia de los grafos.
ß !.&(c1c#.&(: Implementación de los algoritmos FIFO y LIFO.
ß )&2#(: Implementación de grafos; una serie de vértices unidos mediante una serie de
arcos o aristas.

  c

Es la propiedad que permite subdividir una aplicación en partes más pequeñas (llamadas
módulos), cada una de las cuales debe ser tan independiente como sea posible de la aplicación en
sí y de las restantes partes, estos módulos que se puedan compilar por separado, pero que tienen
conexiones con otros módulos. Al igual que la encapsulación, los lenguajes soportan la
Modularidad de diversas formas.

La forma más fácil de almacenar el contenido de una variable en memoria en tiempo de ejecución
es en memoria estática o permanente a lo largo de toda la ejecución del programa.

No todos los objetos (variables) pueden ser almacenados estáticamente.



ara que un objeto pueda ser almacenado en memoria estática su tamaño (número de bytes
necesarios para su almacenamiento) ha de ser conocido en tiempo de compilación, como
consecuencia de esta condición no podrán almacenarse en memoria estática:

* Los objetos correspondientes a procedimientos o funciones recursivas, ya que en tiempo de


compilación no se sabe el número de variables que serán necesarias.

* Las estructuras dinámicas de datos tales como listas, árboles, etc. ya que el número de
elementos que las forman no es conocido hasta que el programa se ejecuta.

Las técnicas de asignación de memoria estática son sencillas.

A partir de una posición señalada por un puntero de referencia se aloja el objeto X, y se avanza el
puntero tantos bytes como sean necesarios para almacenar el objeto X.

La asignación de memoria puede hacerse en tiempo de compilación y los objetos están vigentes
desde que comienza la ejecución del programa hasta que termina.

En los lenguajes que permiten la existencia de subprogramas, y siempre que todos los objetos de
estos subprogramas puedan almacenarse estáticamente se aloja en la memoria estática un
registro de activación correspondiente a cada uno de los subprogramas.

Estos registros de activación contendrán las variables locales, parámetros formales y valor
devuelto por la función.

Dentro de cada registro de activación las variables locales se organizan secuencialmente. Existe
un solo registro de activación para cada procedimiento y por tanto no están permitidas las llamadas
recursivas. El proceso que se sigue cuando un procedimiento p llama a otro q es el siguiente:

1. p evalúa los parámetros de llamada, en caso de que se trate de expresiones complejas, usando
para ello una zona de memoria temporal para el almacenamiento intermedio.
or ejemplos, sí la
llamada a q es q((3*5)+(2*2),7) las operaciones previas a la llamada propiamente dicha en código
máquina han de realizarse sobre alguna zona de memoria temporal. (En algún momento debe
haber una zona de memoria que contenga el valor intermedio 15, y el valor intermedio 4 para
sumarlos a continuación). En caso de utilización de memoria estática ésta zona de temporales
puede ser común a todo el programa, ya que su tamaño puede deducirse en tiempo de
compilación.

2. q inicializa sus variables y comienza su ejecución.

Dado que las variables están permanentemente en memoria es fácil implementar la propiedad de
que conserven o no su contenido para cada nueva llamada


c
c
 c
 c

La forma más fácil de almacenar el contenido de una variable en memoria en tiempo de ejecución
es en memoria estática o permanente a lo largo de toda la ejecución del programa.

No todos los objetos (variables) pueden ser almacenados estáticamente.



ara que un objeto pueda ser almacenado en memoria estática su tamaño (número de bytes
necesarios para su almacenamiento) ha de ser conocido en tiempo de compilación, como
consecuencia de esta condición no podrán almacenarse en memoria estática:

* Los objetos correspondientes a procedimientos o funciones recursivas, ya que en tiempo de


compilación no se sabe el número de variables que serán necesarias.

* Las estructuras dinámicas de datos tales como listas, árboles, etc. ya que el número de
elementos que las forman no es conocido hasta que el programa se ejecuta.

Las técnicas de asignación de memoria estática son sencillas.

A partir de una posición señalada por un puntero de referencia se aloja el objeto X, y se avanza el
puntero tantos bytes como sean necesarios para almacenar el objeto X.

La asignación de memoria puede hacerse en tiempo de compilación y los objetos están vigentes
desde que comienza la ejecución del programa hasta que termina.

En los lenguajes que permiten la existencia de subprogramas, y siempre que todos los objetos de
estos subprogramas puedan almacenarse estáticamente se aloja en la memoria estática un
registro de activación correspondiente a cada uno de los subprogramas.

Estos registros de activación contendrán las variables locales, parámetros formales y valor
devuelto por la función.

Dentro de cada registro de activación las variables locales se organizan secuencialmente. Existe
un solo registro de activación para cada procedimiento y por tanto no están permitidas las llamadas
recursivas. El proceso que se sigue cuando un procedimiento p llama a otro q es el siguiente:

1. p evalúa los parámetros de llamada, en caso de que se trate de expresiones complejas, usando
para ello una zona de memoria temporal para el almacenamiento intermedio.
or ejemplos, sí la
llamada a q es q((3*5)+(2*2),7) las operaciones previas a la llamada propiamente dicha en código
máquina han de realizarse sobre alguna zona de memoria temporal. (En algún momento debe
haber una zona de memoria que contenga el valor intermedio 15, y el valor intermedio 4 para
sumarlos a continuación). En caso de utilización de memoria estática ésta zona de temporales
puede ser común a todo el programa, ya que su tamaño puede deducirse en tiempo de
compilación.

2. q inicializa sus variables y comienza su ejecución.

Dado que las variables están permanentemente en memoria es fácil implementar la propiedad de
que conserven o no su contenido para cada nueva llamada


c
c
 cc

La memoria dinámica es un espacio de almacenamiento que se solicita en tiempo de ejecución. De


esa manera, a medida que el proceso va necesitando espacio para más líneas, va solicitando más
memoria al sistema operativo para guardarlas. El medio para manejar la memoria que otorga el
sistema operativo, es el puntero, puesto que no podemos saber en tiempo de compilación dónde
nos dará huecos el sistema operativo (en la memoria de nuestro
). Es también llamada
almacenamiento libre (freestore) y en estos casos el programador solicita (new) memoria para
almacenar un objeto y es responsable de liberarla (delete) para que pueda ser reutilizada por otros
objetos.

Es aquella que se reserva en tiempo de ejecución después de leer los datos y de conocer el
tamaño exacto del problema a resolver. El sitio donde se almacenan los objetos se le denomina
HEA
= MONTÍ ULO pero el sitio preciso donde se encuentra tal montículo depende del
compilador y el tipo de puntero utilizado en l reserva de memoria dinámica.

untero (apuntador): un puntero o apuntador es un tipo especial de variable que almacena el valor
de una dirección de memoria la cual puede ser de una variable individual, de un elemento de un
arreglo, una estructura u objeto de una clase y se anota de la siguiente manera:

Tipo de apuntador + nombre de la variable.

ß Int *
int; puntero a un entero.

ß har *
char; puntero de carácter.

ß Fecha *
fecha; puntero objeto de la clase fecha.

Independientemente del tamaño del objeto apuntado por una variable puntero el valor almacenado
por esta será el de una única dirección de memoria, por este motivo no existen diferencias
sintácticas entre punteros a elementos individuales y punteros a elementos a un arreglo o una
clase.

Sintaxis para requerir y liberar memoria dinámica

&)!&'.%c!+$!3!$-&.c))&1c$%c%.%4%+ #(c
àeserva de memoria int * a = new int; int * a = new int [N];
Liberación de memoria delete a; delete [] a;
c c
 c

c
c
 c

La recursión permite definir un objeto (problemas, estructuras de datos) en términos de sí mismo.


asos típicos de estructuras de datos definidas de manera recursiva son los árboles y las listas
ligadas. Algunos ejemplos de problemas que se definen recursivamente son el factorial de un
número, la serie de Fibonacci, etc.

àecursión evidentemente se fundamenta en la posibilidad de definir un conjunto infinito de objetos


con una declaración finita. Igualmente, un número infinito de operaciones computacionales puede
describirse con un programa recursivo finito, incluso en el caso de que este programa no contiene
repeticiones explícitas. Un subprograma que se llama a sí mismo se dice que es recursivo.

Un ejemplo clásico donde se presenta la recursividad es en la definición de un factorial: El factorial


de N es la multiplicación de N por el Factorial de N-1.

Sea eso: Factorial(N) = N * Factorial(N-1)

Nótese que la definición de la función se realiza en base a si misma.


ara que la ejecución de este
código sea posible, es necesario definir un caso base, en el caso del factorial seria: Factorial(0) =
1.

De este modo se tiene que:

Factorial(N) = IF(N==0) 1 ELSE N*Factorial(N-1)

àO EDIMIENTOS àE UàSIVOS
Muchas veces nos encontramos con problemas que necesitan la implementación de
procedimientos que se invocan (mandan a llamar) a si mismos. Estos procedimientos o funciones
se llaman recursivos.

Un ejemplo claro de la recursividad es la implementación de un menú recursivo, donde el usuario


escoge su opción, y después de ejecutarse las instrucciones asociadas a esa opción, el programa
regresa al menú principal para que el usuario escoja otra opción. Además, esto nos ayuda para
permitir al usuario ingresar nuevamente la opción, si lo que ingreso antes era incorrecto.

La recursividad en una función o procedimiento no solo nos sirve para implementar funciones cuya
definición matemáticamente hablando es recursiva, o para ejecutar menús recursivos que tienen
que ejecutarse varias veces, sino para implementar ciclos.

I LOS
Un ciclo es una ejecución repetida de un set de instrucciones, y generalmente esta asociado a una
condición, ya que de alguna manera el programa debe de saber cuando parar de ejecutar
repetidamente. La definición de un ciclo depende de tres cosas importantes:
- ondición: omo se había dicho antes, la repetición de instrucciones depende de una condición
que indica cuantas veces se deben repetir o, hasta cuando se deben repetir. En un ciclo podemos
tener dos tipos de condición: la condición que describe cuando debe para el ciclo: y la condición
que describe si el ciclo debe seguir.
- Instrucciones: El set de instrucciones a repetirse en cada una de las iteraciones. Es necesario
que antes de definir un ciclo tengamos claro cuales van a ser la instrucciones que se repetirán.
- Step:
uede ser que en nuestro ciclo existan variables que sufran variaciones de iteración en
iteración, es decir que cambien de valor cada vez que se repiten las instrucciones. A estos cambios
se les llaman steps, y debemos tenerlos claros ya que la mayoría de veces, los resultados
dependen de los mismos.

EJEM
LOS DE ASOS àE UàSIVOS

)#*%$!4!%+ #(c %*-)(!3#(

&5c %*-%+*!&c !'#+&**!


La secuencia de FIbonacci es aquella secuencia de enteros donde cada elemento es la suma de
los dos anteriores.

0 1 2 3 4 5 6 7 8 ..... <--- fib


0,1 ,1 ,2 ,3 ,5 ,8 ,13 ,21 ,... ,

%2!+!*!6+c %*-)(!3&
if n == 0 or n == 1 entonces
fib(n) = n
if n >= 2 entonces
fib(n) = fib(n-2) + fib(n-1) //Llamadas recursivas

.7#)! 4#c $%c .&c %*-%+*!&c !'#+&**!


Función FIB(n)
Inicio
Si n == 0 o n == 1 entonces
FIB<--n
Si No
FIB<--Fib(n-2)+FIB(n-1)
Fin_Si
Fin_Funcion

Ejemplo:
n=2
fib(2)=fib(2-2)+fib(2-1)
fib(2)=fib(0)+fib(1)
fib(2)=0+1
fib(2)=1

)#*%$!4!%+ #(c %*-)(!3#(


1) Función Factorial
2) Secuencia Fibonacci
3) Torres de Hanoi
4) Búsqueda Binaria
.
.
.

'5c #))%(c $%c &+#!


Se tienen tres torres y un conjunto de n discos de diferentes tamaños. Inicialmente los discos están
ordenados de mayor a menor en la primer torre. El problema consiste en pasar los discos a la
tercer torre utilizando la segunda como auxiliar.

àeglas:
1) En cada movimiento solo puede moverse un disco.
2) No puede quedar un disco mayor sobre uno menor.

Instrucciones (Fig.1)
Mover 1 disco de A a B.
Mover 1 disco de A a .
Mover 1 disco de B a .

.7#)! 4#c $%c .&(c #))%(c $%c &+#!

rocedimiento Hanoi(N,OàIGEN,AUXILIAà,DESTINO)
Si N=1 entonces
Escribir "Mover un Disco de",OàIGEN,"a",DESTINO
Si No
regresar Hanoi(N-1,OàIGEN,DESTINO,AUXILIAà) //Llamada recursiva
Escribir "Mover Disco de"OàIGEN,"a",DESTINO
regresar Hanoi(N-1,AUXILIAà,OàIGEN,DESTINO) //Llamada recursiva
Fin_Si
Fin_
rocedimiento

# & Declarara un contador --> uantos Movimientos.

*5c /(0-%$&c !+&)!&


onsidere un arreglo de elementos en el cual los objetos se han colocado en cierto orden. Al
aplicarle la búsqueda en este arreglo primero comparara el elemento que se busca con el que se
encuentra en el centro del arreglo, si son iguales la búsqueda terminara con éxito, si no si el
elemento del medio es mayor que el que se busca el proceso de búsqueda se repite en la primera
mitad del arreglo, si no el proceso se repite en la segunda mitad del arreglo.

.7#)! 4#c $%c .&c /(0-%$&c !+&)!&


if(Low>High)
{
return -1//No se encontró el elemento X en el arreglo
}
else
{
Mid=(Low+High)/2
if(X==A[Mid])
{
return (Mid)//Se localizo el elemento en el arreglo
}
else
{
if(X<MID)<> <= A[Mid])
{
BusquedaBinaria(X,Low,Mid-1)
}
else
{
BusquedaBinaria(X,Mid+1,High)
}
}
}

Ejemplo:
A={1,3,4,5,17,18,31,33}
Low=0
High=7
X=? --->Elemento a Buscar