Sunteți pe pagina 1din 101

Especificacin

Algoritmos: secuencia ordenada y finita de pasos que realiza un cmputo dado un estado
inicial, una vez ejecutados los pasos se llega a un estado final.
En el contexto de la materia, un problema es una descripcin abstracta de un objetivo a
alcanzar a partir de ciertas condiciones iniciales.
Y su solucin ser un algoritmo que satisfaga esa descripcin, es decir, que dados los datos
en cuestin, alcance el objetivo descrito.
De esta forma, la especificacin de un problema puede ser entendida como un estado
inicial y un estado final.
El estado inicial (potenciales entradas) y final (salidas esperadas) de un algoritmo, no es
una declaracin de intenciones, sino un contrato que se debe cumplir antes de invocar a la
funcin.
Estado inicial: Delimitacin del universo sobre el cual puede aplicarse la funcin. No es
que puedo aplicarla pero doy un mensaje de error. Programas que transforman el estado de
una mquina de cmputo no hablan de la relacin con el usuario. Mensajes de error y
excepciones son otro tema.
El estado inicial es {true} cuando siempre puedo aplicar esa funcin sobre cualquier
entrada (la restriccin implcita estara en los datos de entrada, por ejemplo, deben ser
nmeros).
Hay que encontrar una forma de formalizar matemticamente una pieza de software.
Programming in the large (gran equipo de trabajo, divisin en mdulos).
Las herramientas que utilizamos deben preservar una relacin con los problemas que
queremos resolver.
Tipo Abstracto de Datos (TAD):
Es una herramienta que sirve para recortar la realidad. Caracterizacin axiomtica de una
clase de lgebra.
Caracteriza en forma rigurosa y formal los aspectos relevantes de un fragmento de la
realidad.
Tipo en tanto a que identifica la coleccin de cosas que comparten el comportamiento
descrito.
Es una herramienta matemtica que nos da la rigurosidad y formalidad necesarias para
describir el problema a resolver.
Desde el punto de vista histrico es uno de los primeros intentos por abordar la
problemtica de describir formalmente el comportamiento de una pieza de software.
Construimos lgebras que se comportan como (reflejan la info algebraica que subyace
al problema).

Hay de desarrollar una especie de sentido comn, saber cuales son los factores relevantes y
tratar de embeberse del dominio del problema. Observar el comportamiento colectivo de
determinados objetos del mundo real. Tratar de caracterizar las cosas y cmo se relacionan
entre s para resolver el problema.
Queremos expresar nuestro problema a partir de los tipos de las cosas que intervienen en l.
Establecer una caracterizacin formal del comportamiento algebraico.
Partimos de un conjunto de reglas que nos permiten construir un tipo de datos.
Cules son los conceptos que intervienen en el proceso del problema?
No prefijar una estructura antes de saber el problema, porque prefijamos una nica manera
de resolverlo a partir de la estructura elegida.
Identificamos distintos tipos. La separacin permite pensar en forma modular el problema a
partir de problemas de menor complejidad cuyas soluciones se pueden componer para
resolver el problema original. Luego resta saber como caracterizar formalmente el
comportamiento de cada tipo identificado.
Ejemplo: tenemos la percepcin de que es una facultad de los nmeros ser sumables.
Ponemos en el centro del universo las cosas que nos interesan, y estas tienen propiedades
que les son intrnsecas.
Lgica trivaluada
Se tienen valores de verdad: true, false e indefinido.
Indefinido significa que algo NO puede ser evaluado computacionalmente.
Introducimos nuevos operadores lgicos que consideran esta situacin al ser evaluados.
Operadores bsicos: forzamos una decisin en funcin de la info que tenemos.
Embebimos la nocin de orden en el comportamiento (?)
Por ejemplo tenemos la funcin:
F(a,b,c) = (b!=0) L (a/b == c) que nunca evala a indefinido.
Funciones totales: cuando uno las define, estn definidas para todo el dominio).
Sean {Ti} con 0 <= i <= n un conjunto de tipos, luego todo smbolo de funcin f tiene un
tipo que se denota como:
F: T1 x x Tj -> T(j+1)
Que quiere decir que f toma como argumentos j elementos de los tipos T1 a Tj
respectivamente y retorna un elemento de T(j+1)
Lgica de primer orden:
Uno solo es capaz de hablar de las cosas en tanto puede denotarlas. Conjunto de trminos
es lo que uso para denotarlas.
Una funcin debe devolver siempre el mismo resultado para la misma entrada.
La clave de la definicin de las funciones, del comportamiento, est en los axiomas.
Definimos nuestro lenguaje lgico y a partir de el los acciones.

Los nombres no determinan unicidad, hay otras cosas que se comportan igual.
Las variables van a ser consideradas como trminos del lenguaje.
Biyeccin: si todos los elementos del conjunto de salida tienen una imagen distinta en el conjunto de llegada, y a
cada elemento del conjunto de llegada le corresponde un elemento del conjunto de salida.
=> Si hay biyeccin tengo suficientes nombres para todos los elementos

Sean X un conjunto de variables (cada una con un tipo) y {fi} con 0<= i <= m, se define
Term(X, {fi}) como el conjunto de trminos que satisface:
- todo x en X pertenece a Term(X, {fi}) (x simbolitoque uso como variable y sirve
para denotar elementos)
- dada f: TI x x Tj -> T(j+1) en {fi} y tI, , tj en Term(X, {fi}), entonces f(ti,tj)
pertenece a Term(X, {fi}) (Terminos ground: son los trminos que se constituyen con
las funciones)
Se define el conjunto de frmulas bien formadas Form(X, {fi}) como:
- todo t, t en Term(X, {fi}), t t pertenece a Form (X, {fi}) (igualamos dos trminos
cualesquiera. No hay una nocin predefinida de igualdad sino que la damos nosotros)
- dados P en Form (X, {fi}), y x en X => P, P Q, P Q, P L Q, P L Q, x P x P
a Form(X, {fi})
Se denomina sentencia a una frmula sin variables libres
En una gran cantidad de casos se pretende evaluar sobre un subconjunto determinado de los
trminos de un tipo.
Los luegos se utilizan para restringir el dominio sobre el que se aplican las cosas. P es
la restriccin del dominio Q:
( x:T) (P(x) L Q(x)) vale si existe un trmino T tal que, adems se encuentra en el
subconjunto de los que satisfacen P y adems satisface la propiedad Q.
( x:T) (P(x) L Q(x)) vale si la totalidad de los trminos en T que se encuentran en el
subconjunto de los que satisfacen P adems satisfacen la propiedad Q.
La existencia de algo solo puede estar argumentada en tanto ese algo pueda ser
expuesto. Si el universo est vaco no puedo mostrar un elemento de ese existencial.
Vamos a encapsular el comportamiento dentro de los tipos de datos.
TDA:
NOTA: = es una funcin definida que devuelve TRUE o FALSE. es un igualador que se deriva de los
axiomas (es demostrable como igual a partir de estos)

Gnero: Nombre que va a adoptar nuestro tipo de datos (conjunto de valores del tipo). En
general va a haber uno solo, pero podran ser ms.
Exporta: Detalla qu operaciones y gneros se dejan a disposicin de los usuarios del tipo,
sera el equivalente a la parte pblica de las clases. Exportamos el tipo de datos que
estamos construyendo para que otros lo puedan usar.
Parmetros formales: Singulariza las propiedades que debe satisfacer el gnero sobre el
que es paramtrico el tipo. Ejemplo: conj () sera el parmetro formal?
TAD secu[T]
Gnero secu [T]
Generadores: Son las funciones/operaciones que permiten construir los trminos del tipo
(crear nombres para los individuos con los que vamos a trabajar). Tengo que ser capaz de
construir al menos tantos trminos como los que quiera denotar (todo trmino del tipo debe
poder ser construido a travs de una combinacin del conjunto de generadores => es
completo)
Si agrego ms generadores de los necesarios puedo tener sinnimos y luego debo
asegurar que los sinnimos siempre sean equivalentes. Puede pasar que el conjunto de
generadores naturalmente tenga sinnimos (por ej, el conjunto - Un conjunto no tiene orden
entre los elementos, y no tiene elementos iguales). Minimalidad!
Minimal no es lo mismo que mnimo, minimal quiere decir que no tiene que sobrar ninguno,
no necesariamente es mnimo.
Los generadores no definen el comportamiento, solo construyen elementos observables
Observadores bsicos: Son aquellas operaciones que, utilizadas en conjunto, nos permiten
distinguir si dos instancias del tipo son iguales o no.
Son funciones capaces de distinguir toda caracterstica relevante acerca de los trminos.
Permiten mirarlos y extraer informacin. En conjunto identifican al trmino y los separan
entre los que tienen igual o distinto comportamiento. (dos cosas observacionalmente
iguales deben comportarse igual)
Es importante elegir un conjunto razonable (minimal) de observadores.
Son las propiedades que nos interesan de las cosas. La observacin est estrictamente
relacionada con la estructura sintctica del elemento.
Esto se rompe con el conjunto porque por ejemplo:
{a} U ({a} U C) =obs {a} U C
No hay unicidad de nombres, tengo dos nombres distintos para lo mismo. Este es el ncleo
para comprender la semntica observacional.

Semntica lgica, desarrolla una serie de problemas lgicos de significacin, estudia la relacin entre
el signo lingstico y la realidad. Las condiciones necesarias para que un signo pueda aplicarse a un objeto, y
las reglas que aseguran una significacin exacta.

Sintaxis: cmo definir frmulas bien formadas (frmulas como cadenas de smbolos alfabeto, lenguaje)

Semntica: cmo interpretar esas frmulas, como asignarles un valor de verdad (frmulas como
enunciados que pueden ser verdaderos o falsos valuaciones)

Al permitir poner de relieve las caractersticas que distinguen dos trminos, es posible
formular una nocin de igualdad basada en estas caractersticas:
Igualdad observacional: t es igualmente observacional a t entonces t es indistinguible de
t a partir de las funciones observacionales, y para todo f, f(t) es igualmente observacional a
f(t), si no, f no es funcin.
Dos trminos son iguales sii se verifica un predicado descrito en funcin de los
observadores bsicos.
Propieda reflexiva
La propiedad reflexiva establece que para cada nmero real x, x = x.
Propiedad simtrica
La propiedad simtrica establece que para todos los nmeros reales x y y,
si x = y, entonces y = x.
Propiedad transitiva
La propiedad transitiva establece que para todos los nmeros reales x, y, y z,
si x = y y y = z, entonces x = z.
Propiedad de sustitucin
Si x = y, entonces x puede ser reemplazada por y en cualquier ecuacin o expresin.

La igualdad observacional cumple con una relacin de equivalencia reflexiva, simtrica y


transitiva.
Tiene que ser una congruencia (ms fuerte que equivalencia), si t =obs t entonces para toda
funcin f(t) =obs f(t) si no se cumple esto, no es una funcin
Todos los trminos que trabajamos son construcciones finitas (si voy achicando el trmino
llego a un caso base)
Si algo en mi trmino/instancia del TAD cambia y yo lo puedo ver, entonces no es
el mismo trmino. Para esto sirven los observadores.
Igualdad sintctica: los objetos son distinguibles a partir de tener nombres diferentes.
Otras operaciones: son aquellas operaciones adicionales que caracterizan algn
comportamiento esperado del tipo. Deben ser consistentes con lo que me responden los
observadores. Respetar la congruencia.
Deben brindar usabilidad. Los generadores y observadores no le importan al usuario
Axiomas: Son las reglas que definen matemticamente el comportamiento de las
operaciones identificadas.

Usa: manera de importar otro tipo de datos.

Metodologa
La igualdad observacional o en su defecto los observadores bsicos son un punto de
partida ideal. Debido a que identifican cuando dos cosas son iguales (o diferentes) exhiben
todo el comportamiento relevante del tipo.
Luego debemos elegir un conjunto completo de generadores. Operaciones que nos
permiten construir todos los trminos de inters del tipo.
Los axiomas deben ser razonables:
1. El conjunto de axiomas es completo para el conjunto de trminos.
2. No hay dos axiomas que apliquen y den resultados diferentes.
3. Las recursiones terminan.
Debe haber completitud: un axioma por cada generador identificado, de modo que para
todo trmino la operacin este definida. (Siempre que haya un trmino y una funcin
que tenga que estar definida sobre el mismo, haya un axioma que aplique)
No ambiguos: Para cada trmino construible un y solo un axioma de la definicin
aplica, luego no es posible obtener valores diferentes.
Terminacin: Tener bien definidos los casos bases y para todo axioma recursivo el
trmino de la derecha es de menor complejidad que el de la izquierda de modo que no
pueda existir una recursin infinita. Entonces tenemos computabilidad de los resultados
que queremos. Establece un pie a partir del cual la implementacin es posible a travs
de algoritmos.
Los observadores bsicos siempre se axiomatizan sobre los generadores para definir el
comportamiento elemental del tipo.
Idealmente las otras operaciones deben axiomatizarse sobre los observadores bsicos.
De esta forma se garantiza que nunca una de estas operaciones puede distinguir dos
cosas que son iguales
ESTO CIERRA CON EJEMPLO DE CONJUNTO VER HOJAS 6 y 7 DE LA
CARPETA
INDUCCIN
Induccin y recursin son dos caras de la misma moneda, Cundo? Qu? => derivar
estructuralmente propiedades.
Extrapolar una propiedad de un subtrmino al trmino completo.
Extraer propiedades generales a partir de observaciones particulares.
La induccin es un mtodo (cientfico) que se basa en derivar reglas generales a partir de:
- desde un punto de vista histrico: observaciones particulares.
- Desde un punto de vista matemtico a partir de probar que: si una propiedad vale para
un elemento, entonces esto implica que vale para todo otro que lo contenga estrictamente.

Comentario: Notas de la carpeta,


hoja 7. VER

Uno tiene que construir el argumento formal por el cual las cosas valen, ejemplo:
( n, m, p: nat) (suma(n, suma(m,p)) = suma(suma(n,m), p))
Elijo una variable, la p. Esta ocupa el lugar donde los axiomas son inductivos
(cuantificador). Mi recursin est hecha sobre uno de los parmetros.
( p: nat) (P (p))
P(x) = ( n, m: nat) (suma(n, suma(m,x)) = suma(suma(n,m), x))
Es una manera de formalizar la eleccin de la variable.
Caso base / Caso inductivo
La induccin estructural no me permite probar cosas sobre dos trminos, tengo que
probar la propiedad sobre uno (n, m o p en este caso)
Con los rboles hay ms de un paso inductivo
Para que esto funcione debe tratarse de un conjunto bien ordenado. Esto es si existe una
relacin binaria que:
a) ordena totalmente los elementos y b) es una relacin bien fundada.
Se dice que una relacin binaria en un conjunto es bien fundada si existe un elemento
mnimo 0 tal que para todo otro elemento t, el par <t,0> no est en la relacin.
No se puede hacer un argumento similar para los nmeros reales, para que funcione hay
que tener un conjunto bien ordenado. La relacin de orden entre los elementos del
conjunto es porque necesitamos una nocin de inclusin de trminos.
Que para todo par de elementos me pueda decir cual est antes o despus (relacin
total).
El argumento se puede usar un numero finito de veces para que permita tener un
argumento cerrado, entonces al final tengo un caso base (el mnimo en la relacin de
orden el mnimo que obtengo al pelar una cantidad finita de veces)
Funciona porque dado un orden entre los generadores, extendemos ese orden a secuencias
finitas de generadores, es decir, si pensamos a los generadores como letras, construimos
el orden lexicogrfico de trminos
Primero los generadores base (pueden tomar argumentos de otro tipo pero no son
recursivo), luego se ordenan los generadores recursivos y por ltimo se construye un
orden derivado de eso a palabras construidas con eso.
Ej: 0 < Suc(0) porque 0 es < que Suc.
Puedo construir un orden lexicogrfico a partir del orden de los generadores
g1(g2(g3()))
Lema: para todo par de trminos t, t distintos, o bien t > t o bien t > t
Lema: Existe un elemento mnimo (se toma como dicho elemento al generador no
recursivo que sea menor bajo la relacin > - o el que cay primero segn el orden que
sortee)

Comentario: Ese asunto de la


cebolla

Teorema: Los conjuntos de trminos construidos con el lenguaje de TADs con el que
trabajamos son conjuntos bien ordenados.
Corolario: Los conjuntos bien ordenados no poseen cadenas (respecto de >) descendentes
infinitas.
Los trminos tienen una estructura finita entonces no hay cadenas descendentes
infinitas ya que en algn momento termino.
Si el argumento inductivo dice P(2) => P(3), probemos P(2) (modus ponens)
P(0) P(0) => P(1) (m.p.)
P(1) P(1) => P(2) (m.p.)
Etc
Es una cadena descendente finita hasta le caso base.
Las relaciones entre elementos de conjuntos se dan en muchos contextos y, en informtica, aparecen con
frecuencia en programacin, bases de datos informticas, etc.
1.1. Relaciones binarias.
Definicin 1.1.1. Sean A y B dos conjuntos. Una relacin (binaria) R de A en B es un subconjunto de A B:
R A B = {(a, b)/a A, b B}
Escribiremos a R b para indicar que (a, b) R y aR b 6 para expresar que (a, b) / R. Si a R b diremos que a
est relacionado con b.
Si R es una relacin de A en s mismo, i.e., R A A, diremos que es una relacin en A.

El orden lexicogrfico es una relacin de orden que se utiliza para ordenar producto cartesiano de conjuntos
ordenados. Es conocido principalmente por su aplicacin a cadenas de caracteres, por ejemplo en diccionarios o en
la gua telefnica.

En lgica, modus ponendo ponens (en latn, modo que afirmando afirma), tambin llamado modus ponens y
generalmente abreviado MPP o MP, es una regla de inferencia que tiene la siguiente forma:
Si A, entonces B. // A // Por lo tanto, B

Entonces: (a) las recursiones terminan siempre que tengan bien definidos los casos base y
que los casos recursivos que toman un trmino t se resuelvan en funcin de un trmino t tal
que t > t, y (b) tiene sentido pensar que si demuestro una propiedad para los casos base y
que si vale para un trmino, entonces vale para los trminos que lo contienen.
Esquema de induccin:
Sea P una frmula con una nica variable libre x de tipo T, luego, si queremos ver que P
vale para todo elemento de T, debemos probar:
( x:T) P(x)
Sea T un tipo con generadores

C1: args -> T

Cn: args -> T

r1 : t x args -> T
...
rm : t x args -> T

Y P una propiedad con una variable t de tipo T

El esquema se deriva a partir de los generadores. Si pruebo la conjuncin de la


propiedad sobre todos los casos base y la conjuncin de todos los recursivos. La
propiedad se expresa en funciones y las funciones respetan la igualdad observacional.
Entonces si vale para uno, vale para todos los dems.
Implementaciones de pilas, colas y afines. Memoria dinmica
Pila:
Observadores bsicos: vaca?, tope, desapilar
Generadores: vacia, apilar
Otras operaciones: tamao
Cola:
Observadores bsicos: vaca?, prximo, desencolar
Generadores: vacia, encolar
Otras operaciones: tamao
Las pilas y las colas son bastante similares por lo que vamos a trabajar con el TAD Cola.
A las pilas se las llama colas LIFO (last in, first out) y a las colas, colas FIFO (first in, first
out).
Una implementacin posible es usando arreglos. Una cola sera un arreglo, ms un natural
que indica su tamao. Las posiciones del arreglo de n elementos van de 0 a n-1 (por
convencin en este caso).
Instanciamos en floats
Struct {
Nat cant;
Flota elementos[MAX_CANTIDAD]
}
Idea: los elementos vlidos son los que figuran entre la posicin 0 y cant-1.

Una posible implementacin de desencolar es, al sacar el primer elemento, correr todos una
posicin. Esta no es una buena implementacin ya que es extremadamente cara. Cuantos
ms elementos tenemos, ms tarda.
Se podra solucionar agregando a la estructura la variable primero (nat) de modo que en
lugar de que el primero sea siempre 0, vayamos corriendo esta posicin.
Ahora, a diferencia de la implementacin anterior, en esta solo voy a poder meter
MAX_CANT elementos. En la anterior este era el lmite de elementos que podan convivir
en simultaneo ac es el lmite total.
Una posible solucin sera desplazar los elementos en algn momento. Solucin ms
interesante:
Usando aritmtica circular (mdulo). Usamos la misma estructura pero podemos seguir
usando las posiciones que estn antes de c.primero de modo que la posicin a encolar en la
implementacin sera (c.primero + c.cant) mod MAX_CANTIDAD y la posicin a
desencolar sera (c.primero + 1 ) mod MAX_CANTIDAD.
En matemtica, la aritmtica modular es un sistema aritmtico para clases de equivalencia de nmeros
enteros llamadas clases de congruencia.
Algunas veces se le llama, sugerentemente, aritmtica del reloj, ya que los nmeros dan la vuelta tras alcanzar
cierto valor llamado mdulo.2
La aritmtica modular puede ser construida matemticamente mediante la relacin de congruencia (elacin entre
dos nmeros enteros a

y b que tienen el mismo resto mediante una divisin euclidiana1 por un nmero natural m

distinto de 0) entre enteros, que es compatible con las operaciones en el anillo de enteros: suma, resta, y
multiplicacin. Para un determinado mdulo n, sta se define de la siguiente manera:3
a y b se encuentran en la misma "clase de congruencia" mdulo n, si ambos dejan el mismo resto si
los dividimos entre n, o, equivalentemente, si a b es un mltiplo de n.

Esta relacin se puede expresar cmodamente utilizando la notacin de Gauss: a = b (mod n)


As se tiene por ejemplo 63 = 83 (mod 10)
ya que ambos, 63 y 83 dejan el mismo resto (3) al dividir entre 10, o, equivalentemente, 63 83 es un mltiplo de
10. Se lee:3
63 es congruente con 83, mdulo 10, o 63 y 83 son congruentes uno con otro, mdulo 10.

Con esta misma idea podramos implementar una secuencia, pero la operacin que elimina
a un elemento de la misma sera cara porque involucrara desplazamientos para no dejar
huecos.
En cuanto al tamao (si no alcanza, o sobra). Algunos lenguajes proveen arreglos
redimensionables, el mecanismo consiste en crear uno ms grande y luego copiar los
elementos.
Hasta ac estamos trabajando con memoria esttica, asignada por el compilador al
compilar el programa.
Al redimensionar lo que se hace es conseguir un espacio ms grande en la memoria y
volver a copiar todo en el nuevo espacio.
Memoria Dinmica

Es la memoria que le pedimos al sistema operativo cuando el programa ya se est


ejecutando. Tanto el espacio como lo que contiene es la variable:
Variable matemtica: Valor fijo pero desconocido. Ejemplo: ( x) ( x + 1 > x)
Variable computacional: Objeto que contiene un valor.
Z = x + 8 z sera el cajn y x el valor.
A la izquierda de la asignacin las variables son lugares de memoria. A la derecha, son
el valor de su contenido.
Abstractamente la memoria es un vector de bytes. Ejemplo [064mb]
Las variables tienen un tipo que determina, entre otras cosas su tamao (es decir el espacio
que esa variable ocupa.
A cada programa en ejecucin le corresponde un fragmento, dado por las variables estticas
que utiliza.
Si tenemos por ejemplo un programa con dos variables int y un float, y suponemos que un
int usa 2 bytes y un float 4, ese programa usa 8 bytes de memoria: M[comienzo
comienzo + 7].
Conclusin: podemos utilizar una variable para referirnos a su valor o al espacio de
almacenamiento que representa (x = 3, z = 5, z = x).
En general las posiciones de memoria son consecutivas, a nosotros no nos importa.
Cmo me doy cuenta de cul es el espacio de memoria que el S.O. me dio? cmo lo
uso?
Cuando le pido memoria al sistema operativo le paso una variable que ya tena definida
en mi programa (puntero) y le digo que me devuelva ah la ubicacin del espacio que
me dio en la memoria (es decir, dnde empieza el espacio).
La memoria se direcciona usando nmeros enteros.
Si pierdo el puntero no puedo usar la memoria ni liberarla.
Hasta ahora vimos variables estticas, existen tambin las variables dinmicas sirven,
entre otras cosas, para los casos en que no sabemos de antemano el tamao de la entrada
(podemos por ejemplo pedirle al usuario una cantidad C de enteros que va a ingresar,
reservar esa memoria, y luego leerlos y almacenarlos.
Punteros
Sirven para referirnos a posiciones arbitrarias de la memoria y permiten utilizar estructuras
dinmicas.
En el comienzo de los tiempos se peda memoria pidiendo una cantidad de bytes en
una variable/puntero. Uno indicaba la cantidad necesaria y se pierde la nocin de tipado,
no s qu es lo que va a ocupar esa memoria.
Int x

Punt p
X=3
*p = 7
En c la asignacin dinmica de memoria se hace con MALLOC (memory allocate,
dame memoria (reserv, asign) para alojar de tal tipo tal cantidad.
P = MALLOC(int, 100).
Sobrescribir direcciones de memoria es una tcnica muy comn de intrusin.
Puntero tipado:
Puntero a int p
P = MALLOC(100) -> no hace falta decirle el tipo porque ya lo sabe
En C++ malloc es new.
Para ver el valor al que apunta p: x = *p.
(*p).campo equivale a p->campo.
Si hago p= 400 ahora p apunta a M[400]
Si hago x= 398; p= x ahora p apunta a M[398]
Para asignar un valor debo hacer p = &x; (p apunta a la celda llamada x)
& me devuelve la direccin de memoria en la que vive una variable.
P = &x
Aliasing: dos nombres hacen referencia al mismo objeto. P apunta a x entonces *p y x
son dos nombres para lo mismo.
Si hago *p = &x pongo x en su misma direccin de memoria.
La memoria que pido la tengo que liberar: malloc/free
new/delete
Si no la libero depende del sistema operativo. Hoy en da el SO libera la memoria
cuando termina el programa. Windows 3.11 no liberaba memoria.
Con memoria dinmica, el programa en ejecucin puede usar ms memoria que la
disponible en el sistema (??)
Implementacin de colas con memoria dinmica y punteros:
Struct {
Struct nodo_cola *prim;
Struct nodo_cola *ult;
Nat cant;
}
struct nodo_cola{
float elem;
Struct nodo_cola *prox;
};

Comentario: Chequear esto


porque no se si anot bien

Prim apunta al primer elemento encolado de los que quedan (el ms viejo, el prximo a
salir). Ult apunta al ltimo elemento encolado (el ms reciente) y cada nodo tiene un
puntero al elemento anterior.
El ltimo elemento apunta a NULL (una direccin de memoria que apunta a nada).
Ahora por cada elemento tengo casi el doble de memoria que la implementacin
anterior.
En un arreglo puedo acceder directamente al isimo elemento, mientras que ac tengo
que recorrer uno por uno hasta llegar al isimo.
Funcin auxiliar:
Nuevo_nodo(elemento):
Struct nodo_cola *nodo;
Nodo:= new (struct nodo_cola);
If (nodo == null) Hacer_algo_com_el_problema();
Nodo->prox := NULL;
Nodo->elem := elemento;
Return nodo;
Es una funcin que pide memoria y luego guarda el elemento devolviendo un puntero
hacia el mismo.
Si nodo==NULL quiere decir que no nos dio el espacio en memoria. En sowftwares
crticos (como por ejemplo el de un marcapasos) no es conveniente usar memoria
dinmica. Se utiliza memoria esttica.
Para desencolar, guardo el c.prim en un auxiliar (guardo a dnde apuntaba) y despus lo
borro (libero memoria)
Aux:= c.prim;
c.prim:= c.prim->prox;
delete aux;
En el caso de la cola es razonable tener un nico puntero por nodo porque nos movemos
unidireccionalmente. Para mayor flexibilidad existen tambin las listas doblemente
enlazadas (dos punteros, anterior y prximo).
Tarea: Programar una cola que se comporte como FIFO o LIFO de acuerdo a un parmetro
al constructor (en tiempo de ejecucin).
La implementara sobre una lista doblemente enlazada. Agregar elemento agrega
siempre atrs, y si es FIFO en el caso de que el prximo sea NULL pone prximo al
que agrega y si no lo deja como est y el ltimo es siempre el que agrega, si es LIFO
cada vez que agrega un elemento lo pone como prximo y el ltimo es el que agrega
si es NULL o el que ya estaba si no era null.
Al sacar un elemento saca siempre el prximo y si es FIFO pone como prximo el
siguiente y si es LIFO pone como prximo el anterior.
COMPLEJIDAD

Desde un punto de vista prctico no todo algoritmo que satisface una especificacin da lo
mismo.
Existen dos tipos de complejidad, la temporal y la espacial, y sirven para saber cuanto
nos cuesta resolver un problema en tiempo y espacio respectivamente.
En la materia solo nos preocuparemos por la complejidad temporal.
Medidor de recursos: Cunto tiempo el cpu te asign? Solo considera lo especfico de
mi programa (la ejecucin). No depende de todo lo que se est ejecutando pero s de esa
computadora especfica.
Lo que debe determinar el comportamiento son las estructuras de control que estoy
usando en mi programa y no el lenguaje. Se fija un paradigma independizndonos del
lenguaje.
Cmo podemos medir el costo temporal de un algoritmo?
1. Usando un cronmetro Se suele llamar wall time. Lo bueno es que nos dice
objetivamente cunto tarda, lo malo es que depende de factores completamente ajenos al
programa y los datos. Ni siquiera es confiable entre dos ejecuciones consecutivas.
2. Usando un medidor de recursos Se suele llamar CPU time. Lo bueno es que nos dice
cuntos recursos utilizamos, lo malo es que depende de la computadora especfica; luego si
maana cambio de computadora, cambia el comportamiento.
Contando operaciones elementales!
Se suele llamar complejidad algortmica. Se trata de acotar la cantidad de operaciones
elementales que toma resolver un problema en funcin del tamao de la entrada.
Deberamos encontrar una mtrica que sea independiente de la mquina en la que se
ejecuta e incluso del lenguaje que se est implementando.
Ejemplo A:
void max_min (int *datos, int cant, int &max, int &min){
max = datos[0];
c1
for (int i = 1; i < cant; i++)
cant*c2
if (max < datos[i]) then max = datos[i];
cant*c3
min = datos[0];
c4 = c1
for (int i = 1; i < cant; i++)
cant*c5 = cant*c2
if (min > datos[i]) then min = datos[i];
cant*c6 = cant*c3
}
Las constantes estn vinculadas a un determinado procesador, memoria, etc. Queremos
una mtrica en funcin del tamao de entrada, es lo que determina el costo
computacional. Entonces, vamos a construir una abstraccin matemtica.

Las constantes reflejan el costo de las operaciones elementales en el lenguaje y plataforma


puntual en la que se ejecuta el algoritmo. Es decir, aquello de lo que queremos
abstraernos
Clases de funciones:
Para poder abstraernos de las constantes, debemos poder clasificar las funciones de acuerdo
a su razn de crecimiento
Para ello, lo que se hace es determinar cotas ajustadas por encima y por debajo que
permiten reflejar esta razn.
Ejemplo B
void max_min (int *datos, int cant, int &max, int &min){
max = datos[0], min = datos[0];
2*C1
for (int i = 1; i < cant; i++){
cant*C2
if (max < datos[i]) then max = datos[i];
cant*C3
if (min > datos[i]) then min = datos[i];
cant*C3
}
}
Cunto crece el costo en funcin de la entrada? En C3 por ejemplo hay dos
operaciones, el if y el then, y lo que pasa en el then no se ejecuta siempre. La ejecucin
o no, no depende del algoritmo sino de los datos de entrada.
En el mejor de los casos la cantidad de veces que se ejecuta el then podra ser 0 y nuestro
algoritmo sera ms eficiente.
En el peor de los casos podra ser cant y nuestro algoritmo tendra su peor rendimiento
O podramos asumir que es cant/2 en un caso promedio y tendramos una idea general de
su rendimiento.
Cada una de estas suposiciones nos brinda una mirada sobre el comportamiento de nuestro
algoritmo:
Peor: tendremos la certeza de cul es el mximo tiempo necesario para ejecutar nuestro
algoritmo.
Es una certificacin muy fuerte: nunca va a costar ms que esto.
Mejor: nos brinda una cota de los ms rpido que nuestro algoritmo consigue ejecutar.
Es una cota inferior, no es una garanta, pero tendremos que esperar por lo menos eso.
Promedio: Nos proporciona una mirada equilibrada entre peor y mejor caso del tiempo que
toma ejecutar nuestro algoritmo, esto casi siempre depende de hiptesis adicionales sobre
los datos.
En general vamos a adoptar la postura de calcular el peor caso. Y en principio ese
anlisis se va a calcular a partir de probar la pertenencia de una funcin a una cierta
clase de funciones.
Para cada uno de estos anlisis se puede definir una clase de funciones que se comportan
igual a una dada y as probar si nuestro algoritmo pertenece o no a dicha clase,
caracterizando as su complejidad temporal

La clase O:
O(g(n)) = { f(n) | ( c, x0) ( x0 <= x) (f(x) < c*g(x))}
Dada una funcin g(n) define todas aquellas funciones que estn acotadas por encima
por una constante de g(n).
Lo que importa es que a partir de cierto punto mi funcin queda por debajo de la otra.
Ejemplo:
F(n) = c1 + n c2 + n c2 + c1 + n c2 + n c3
G(n) = 2 c1 + n c2 + 2 n c3
(c2+2 c3) n + 2 c1 O(n)
Las constantes son constantes pero no importa lo que son, importa la funcin. Yo
quiero que 3 n pertenezca a O(n).
La manera de agrupar cosas que tienen constantes diferentes es encontrando una
constante que???
O(3n) = O(n) = O(68n)
La constante no implica cambio en el comportamiento. Lo que me importa es Qu
cosas nada va a poder hacer mejor por mi.
La clase Omega:
(g(n)) = { f(n) | ( c, x0) ( x0 <= x) (c*g(x) < f(x))}
Acota por debajo. Esto caracteriza el comportamiento en el mejor caso. No en el sentido
de la entrada, pero en ningn escenario posible voy a caer por debajo de ese tiempo.
La clase Tita:

(g(n)) = { f(n) | ( c1, c2, x0) ( x0 <= x) (c1*g(x) < f(x) <= c2*g(x))}
F(x) encajonada entre dos constantes por la misma funcin, mejor y peor caso coinciden.
Va a tardar alrededor de eso porque tenemos una variacin en funcin de constantes.
Si tengo un algoritmo cuya funcin caracterstica de la cantidad de las funciones es
f(n) = 3n3 + n + 5
Para probar que f(n) a O(n3) tengo que demostrar que existen c y x0 tales que
( x0 <= x) (f(x) < c*g(x))
Entonces dada la funcin de costo de un algoritmo particular, se puede probar su
pertenencia a una clase de funciones determinada.

Comentario: Qu lo qu ver
qu tendra que ser esto

Aritmtica de rdenes de complejidad


Ahora tomamos el ejemplo A y reemplazamos todas las constantes por O(1).
O(1) es el costo de las operaciones elementales. Si hay una invocacin a otra funcin de
la cual conozco su orden de complejidad podra ser O(n). Las constantes no importan,
slo el orden de complejidad.
Tenemos O(1) + cant*O(1) + cant*O(1) + O(1) + cant*O(1) + cant*O(1) (*1)
Como hacer para que esto se convierta en una nica expresin O(f(n)) que caracterice su
costo.
f(n) + O(g(n)) = O(f(n) + g(n))
f(n) * O(g(n)) = O(f(n) * g(n))
O(f(n)) + O(g(n)) = O(f(n) + g(n))
O(f(n)) * O(g(n)) = O(f(n) * g(n))
Los logaritmos son todos iguales a efectos del clculo de complejidad temporal:
O(log(a)(n)) =
= O(log(b)(n) / log(b)(a)) =
= O(1/log(b)(a) * log(b)(n)) =
= O(log(b)(n))
(*1) queda entonces como O(cant).
La funcin O absorve las operaciones aritmticas, incluso colapsa las clases de
funciones. La multiplicacin responde a la necesidad de una estructura de control que se
va a repetir una cierta cantidad de veces (un ciclo).
La suma, por la composicin secuencial:
P;
Q;
O(P) + O(Q)
O son funciones en una variable, no hay manera de absorber? Una variable sobre otra.
G podra ser en otra variable pero???
El if no est representado, pero no importa. Agarramos la rama ms costosa y
calculamos sobre eso.
Ecuaciones de recurrencia
Se denomina ecuacin de recurrencia a una igualdad de la forma:
T(n) = f(n) * T(g(n))+ h(n)
Denotando que la resolucin de un problema de tamao n requiere resolver f(n)
subproblemas de tamao g(n) tal que la integracin de sus soluciones cuesta h(n).
Ejemplo: T(n) = 2 T(n/2) + n es la ecuacin de ordenamiento para Merge Sort. Agarra
un arreglo que quiero ordenar y si el tamao es mayor a 2 lo puedo partir en 2 y llamo

Comentario: Muy en la nada


todo esto, tendra que ver qu
quiere decir

recursivamente, ordeno una mitad, ordeno otra y despus las voy barajando. Dado un
arreglo de tamao n ordena dos arreglos de tamao n/2 y luego invierte n en ordenarlos.
Para resolver el ms grande veo cuanto me cuesta resolver uno un poco ms chico.
Entonces, nos gustara dada una ecuacin de recurrencia, poder dar una funcin f(n) tal que
T(n) <= f(n)
Es decir; poder aportar una expresin en n (f(n)) que acote por encima al trmino T(n) y as
poder decir que T(n) a O(f(n)).
Existen tres mtodos para resolver ecuaciones de recurrencia:
Mtodo de sustitucin:
Se basa en a) adivinar una funcin y luego b) probar por induccin que efectivamente
esta acota por encima a T(n).
Las cosas recursivas se demuestran por induccin. Este mtodo no me da un mecanismo
para encontrar la funcin que lo caracteriza.
Ejemplo:
T(n) = 2 T(n/2) + n
Queremos probar que pertenece a O(n*log n)

c x0 t| x >= x0 T(n) <= c. n log n


2 T (n/2) + n <= c n log n
2 (c1 n/2 log n/2) + n <= c n log n
por induccin T(n/2) sera c1 n/2 log n/2?
C1 n (log n log 2)<= c n log n
log de la divisin es la resta de los logaritmos
C1 n log n c1 n + n <= c n log n
C1 n log n (c1 1) n <= c n log n
C= c1 + 1
Ecuacin de recurrencia de la longitud de la secuencia T(n) = T (n-1) + c
Mtodo del rbol de recursin:
Normalmente este mtodo es menos compacto que el anterior, resuelve el problema de
adivinar una solucin reemplazando esto por una derivacin que permite llegar a la
funcin que caracteriza la complejidad temporal del algoritmo.
En muchos casos este mtodo se puede utilizar para construir un candidato que luego se
puede demostrar usando la induccin de la misma forma que en el caso del mtodo de
sustitucin.
Ejemplo:

T(n) = 3T(n/4)+n2

T(n)
T(n/4)

T(n/4)
T(n/16)

T(n/16)

T(n/4)
T(n/16)

T(n/24)

T(n/24)

T(n/24)

Los pasos van de 0 (T(n)) en adelante. Como siempre lo divido por 4 la relacin entre la
altura y n es log4 n. n = 4h
En cada paso tengo 3h veces T(algo)
El ltimo nivel es el que me muestra el costo de todos los casos base. Entonces.
Resolver el todos los casos base es:
3 log4 n . O() ->costo del caso base, asumimos que es una constante
3 log4 n + i= 1 hasta log4 n 3 i-1 (n/ 4 i-1)2
3 log4 n + n2 i= 1 hasta log4 n (3 i-1 / 16 i-1)
3 log4 n + n2 i= 1 hasta log4 n 1 (3 / 16 )i
Es una Progresin geomtrica que finalmente resulta en O(n) (ver resolucin en hoja 12
carpeta)

Serie geomtrica 1 + 1/2 + 1/4 + 1/8 + ... converge a 2.

Una progresin geomtrica es una secuencia en la que el elemento se obtiene multiplicando


el elemento anterior por una constante denominada razn o factor de la progresin. Se suele
reservar el trmino progresin cuando la secuencia tiene una cantidad finita de trminos
mientras que se usa sucesin cuando hay una cantidad infinita de trminos, si bien, esta
distincin no es estricta.
As, 5,15,45,135,405 es una progresin geomtrica con razn igual a 3, porque cada
elemento es el triple del anterior. Se puede obtener el valor de un elemento arbitrario de la
secuencia mediante la expresin del trmino general, siendo
el trmino en cuestin,
el
primer trmino y , la razn:

En el ejemplo anterior, el cuarto elemento de la serie es:

Ejemplos de progresiones geomtricas

La progresin 1, 2 ,4 ,8 ,16, es una progresin geomtrica cuya razn vale 2, al igual


que 5, 10, 20, 40.

La razn no necesariamente tiene que ser un nmero entero. As, 12, 3, 0.75,
0.1875 es una progresin geomtrica con razn 1/4.

La razn tampoco tiene por qu ser positiva. De este modo la progresin 3, -6, 12, 24 tiene razn -2. Este tipo de progresiones es un ejemplo de progresin
alternante porque los signos alternan entre positivo y negativo.

Cuando la razn es igual a 1 se obtiene una progresin constante: 7, 7, 7, 7

Un caso especial es cuando la razn es igual a cero, por ejemplo: 4, 0, 0, 0. Existen


ciertos autores que no consideran este caso como progresin y piden explcitamente
que

en la definicin.

Suma de trminos de una progresin geomtrica[editar]


Suma de los primeros n trminos de una progresin geomtrica[editar]
Se denomina como Sn a la suma de los n primeros trminos consecutivos de una progresin
geomtrica:
Si se quiere obtener una frmula para calcular de una manera rpida dicha suma, se
multiplica ambos miembros de la igualdad por la razn de la progresin r.

puesto que
Si se procede a restar de esta igualdad la primera:
ya que todos los trminos intermedios se cancelan mutuamente.
Despejando

De esta manera se obtiene la suma de los n trminos de una progresin geomtrica cuando
se conoce el primer y el ltimo trmino de la misma. Si se quiere simplificar la frmula, se
puede expresar el trmino general de la progresin an como

que expresa la suma de n trminos consecutivos de una progresin geomtrica en funcin


del primer trmino y de la razn de la progresin.
Se puede generalizar el procedimiento anterior para obtener la suma de los trminos
consecutivos comprendidos entre dos elementos arbitrarios
(ambos inclusive):

Suma de infinitos trminos de una progresin geomtrica

Si el valor absoluto de la razn es menor que la unidad


, la suma de los infinitos
trminos decrecientes de la progresin geomtrica converge hacia un valor finito. En efecto,
si

tiende hacia 0, de modo que:

Finalmente, la suma de los infinitos trminos de una progresin geomtrica de razn inferior
a la unidad es:

Mtodo maestro:
Es el recetario para resolver ecuaciones de recurrencia de la forma:
T(n) = a T(n/b) + f(n)
Sean a 1 y b > 1 constantes, sea f (n) una funcin, y sea T (n) la recurrencia que sigue
definida sobre los enteros no negativos
T(n) = aT(n/b) + f(n),
Entonces T (n) puede ser acotado asintticamente como sigue:
1. Si f (n) O(n log b (a)- ) para > 0, entonces T (n) (nlog b (a) ),
2. Si f (n) (nlog b (a) ), entonces T (n) (nlog b (a) log n),
3. Si f (n) O(n log b (a)+ ) para > 0 y af (n/b) < cf (n) para alguna con- stante c > 1 y un n
suficientemente grande, entonces T (n) a (f (n)).
La intuicin del teorema maestro recae en comparar qu parte del algoritmo domina el
costo del problema, es decir, comparar a) la base del rbol de recursin en donde se
resuelven los casos base, o b) la funcin que integra las soluciones parciales en una
solucin final. Esta es la razn por la cual se compara f(n) con la cantidad de casos bases:
n log b (a)
En el primer caso mi funcin est acotada por encima por algo un poco ms chico que
la cantidad de casos base.
En el segundo caso mi funcin est acotada por encima y por debajo por algo
aproximadamente igual al caso base.
Tercer caso est acotada por debajo por algo un poco ms grande que la cantidad de
casos base.
Hay una salvedad importante para hacer: Como se trabaja con cotas asintticas, las
diferencias que se estn caracterizando cuando se realiza la comparacin deben ser
polinomiales en n y por lo tanto, si esto no se cumple el teorema maestro no da respuesta a
la caracterizacin de la complejidad temporal.
Lo mismo ocurre con la condicin de regularidad del caso 3.

Es decir f(n) debe ser polinomial


Qu es la complejidad? Recursos: tiempo y memoria. Escrituras a disco en
algoritmos ms complejos (bases de datos) O(n3)en memoria frente a una escritura
en disco es despreciable.
El caso promedio depende tambin de los datos. La complejidad de las tablas de Hash
se mide en el caso promedio.
En trminos de complejidad, logaritmos de cualquier base son equivalentes.
En la bsqueda secuencial con alfa cambia la complejidad, por ejemplo, si son
strings compararlos es O(tam(string))
Podra hablar del mejor caso y acotarlo por abajo tambin. Omega significa acotar
por abajo, pero no necesariamente es el mejor caso
DISEO JERARQUICO DE TIPOS
Qu significa disear?
* Pasar de la descripcin del qu al problema del cmo
* Considerar aspectos no funcionales, por ejemplo, eficiencia en el tiempo y espacio de
acuerdo al contexto de uso
* Permitir un cambio de paradigma (del utilizado para especificar al utilizado para
programar) que resulte ordenado
En nuestro caso se trata de producir una implementacin en el paradigma imperativo de un
tipo abstracto de datos descrito en un lenguaje de caractersticas lgicas (en particular
funcional).
ConjuntoDeNat
T imp

se explica con

se explica con

Conj[nat]

Ttads

Las implementaciones se explican con una especificacin. La relacin no es simtrica (es


decir la especificacin no se explica con una implementacin)
Qu significa jerrquico?
Que pensaremos la resolucin del cmo a partir de representaciones de un tipo sobre otros
separando responsabilidades en la construccin de la solucin.
ConjuntoDeNat
Se representa con

SecuenciaDeNat
Se representa con

se explica con

Conj[nat]

Comentario: Estara bueno


entender este chino-bsico bien.

punteros
Elijo una estructura para representar a los conjuntos, por ejemplo un abb que me
garantiza que el costo computacional se mantiene cercano al logaritmo. Si es lineal
puede ser una secuencia.
Tengo que acercarme de alguna manera a la arquitectura de mi computadora.
Como abstraccin vemos la secuencia e intuitivamente lo manejamos con punteros.
Para el que utiliza el conjunto la secuencia tampoco es visible.
Elegir una estructura de representacin tiene un costo, dado que a partir de entonces
nuestros algoritmos van a tener un costo computacional relacionado a la estructura que
eleg.
Lenguaje de diseo
Hay cuatro cosas a tener en cuenta, que son de relieve antes de comenzar a disear, por sus
consecuencias sobre el comportamiento de nuestras implementaciones:
* Tipos de datos
Con qu tipo de datos vamos a trabajar, cuales son los primitivos, cual es su
funcionamiento
* Declaracin de operaciones
Los observadores dicen cual es el comportamiento de mis TADs. Cualquier otra
operacin hereda el comportamiento de los observadores. Ejemplo, en secu() tener o
no long como operacin no determina que igual no sea calculable. El comportamiento
es definible. Hay un montn de operaciones definibles como herencia del
comportamiento bsico.
Ejemplo conjuntos nunca vacos
Conjdenat singleton(int n)
{pre}
{res =obs {n} U vaco}
Implemento una operacin que se explica en funcin de mi especificacin matemtica.
Estas situaciones se dan muy poco ya que por lo general uno especifica ad hoc Para
resolver un problema y el diseo es diseo de esa especificacin
* Pasaje de parmetros
En general hay tres tipos:
In: No puedo asignarle valores a eso. Es un dato de entrada y solo puede utilizarse para
hacer operaciones que no modifiquen su valor.
Out:
In/out: Ejemplo: Ag(conjdenat c, int n) si quiero agregar n a c, c debe ser in/out. Si
ambos son de tipo in nos vamos a ver obligados a copiar c, agregar el elemento y
devolver un nuevo conjunto. Tendr que haber una poscondicin res: conjdenat. Tener
que copiar elemento por elemento, todo lo que tiene c a res implica un costo.
Los tres tipos de parmetros tienen un sentido diferente en tanto cada uno de ellos
determina si se van a hacer transformaciones sobre los parmetros pasados o no.

Comentario: Y ac segua algo


que no termin de copiar revisar

Comentario: No entend muy


bien realmente de qu seguan
todas estas cosas de la carpeta.

Si quiero que Ag() tenga orden 1 entonces no voy a poder hacer nada peor que
modificar el conjunto que estamos pasando por parmetro.
F(x) = x2 f(2) = 4
No transform el 2 en 4, reemplaza y resuelve ?
En el sentido imperativo es ms complejo, las variables denotan direcciones de
memoria. Cada instruccin imperativa realiza una pequea modificacin en el estado de
mi pc.

Comentario: Esto ltimo no se


muy bien a qu vena.

* Asignacin.
Accin primitiva por excelencia de los lenguajes imperativos, asignarle algo a la
memoria.
C
Conjdenat c;
C= c;
El significado depende de la semntica que le de al operador igual.
Deep copy: me meto en el conjunto lo recorro y creo otro completamente independiente
pero igual a c. = puede tener semntica de copia o semntica de referencia.
Metodologa de diseo
Desde un punto de vista abstracto disear implica las siguientes tareas:
* Eleccin del tipo a disear
Elegimos una estructura de representacin y la vinculamos con la estructura que
tenamos.
* Introduccin de los elementos no funcionales
Los aspectos no funcionales (ordenes de complejidad, no son solo el tiempo de
ejecucin en funcin de la entrada ?) condicionan la eleccin de la estructura.
* vinculacin entre la representacin y su abstraccin
* Iteracin sobre los tipos restantes
Conjdenat
Interfaz
SRC
Representacin
SecudeNat

^ sec

conj[nat]
abs
^

secu[nat]

Punteros
Es correcto, el tringulo conmuta.
Una operacin binaria es conmutativa cuando el resultado de la operacin es el mismo, cualquiera que sea el
orden de los elementos con los que se opera

ConjdeNat implementa la algortmica de conjunto sobre un contenedor que es la


secuencia. Internamente lo resuelvo de esa manera. La secuencia me sirve para
preservar la coherencia de los punteros. Puede haber muchos niveles.

Comentario: Ac, hoja 13, hubo


varias cosas que me quedaron en el
airey no pas. Esto por el orden
de la carpeta pareciera
corresponder ms bien a Lenguaje
de diseo

Efectivamente cada nivel de abstraccin debera resolver una parte del problema. Si
todas las operaciones deben hacerse en ambos niveles, uno de los dos sobra.
Puedo ir de conjunto directo a punteros, pero podra haber separado ms las unidades
para que quede ms claro
Los aspectos de la interfaz de un tipo describen todo elemento relacionado con los
aspectos de uso de dicho tipo, es decir, toda cuestin referida a lo que resulte visible desde
afuera.
Las pautas de implementacin sern todo aspecto que refiera a cuestiones vinculadas a
los medios a travs de los cuales el tipo garantiza esos aspectos de uso. (la implementacin
hacia adentro).
La definicin de la interfaz de un mdulo de diseo implica tomar en cuenta varias cosas.
Esencialmente debe explicarle al eventual usuario todos los aspectos relativos a los
servicios que exporta.
Documentacin
Servicios exportados: Describe para cada operacin su orden de complejidad, aspectos de
aliasing, efectos colaterales sobre los argumentos, etc.
Para toda operacin del tipo que vamos a disear escribir aspectos relevantes.
Ejemplo: Conj Ag(
, int n)
Doble referencia, lo que pas como valor y el valor modificado. Entonces hay un nico
conjunto que tiene n.
Un aspecto de aliasing es de pronto desde adentro del conjunto tengo un puntero a otra
estructura. Tiene que estar informado ya que despus no puedo destruirlo. Hay que
saber si se agrega por aliasing o por copia. Si es por copia, la responsabilidad de liberar
la memoria es ma.
Efectos colaterales: modificar argumentos pasados por parmetro.
Interfaz: define el paradigma imperativo, las operaciones exportadas junto con su
precondicin y su poscondicin. Esto establecer la relacin entre la implementacin de las
operaciones y su especificacin.
Las precondiciones y poscondiciones se escriben en lenguaje lgico.
Si el lenguaje de implementacin es diferente al lenguaje de especificacin hay una
diferencia entre los valores que pueden tomar las variables imperativas respecto de los
trminos lgicos.
Para vincularlos utilizamos la funcin ^ que para cada valor imperativo nos retorna un
trmino lgico al cual representa, de forma que este pueda participar de los predicados
lgicos que definen el comportamiento formal de las operaciones.
Introducimos una notacin definida como una funcin que va del gnero imperativo GI al
gnero GT correspondiente a su especificacin:
^: GI GT
En el mundo de la implementacin se preserva la igualdad observacional.

Comentario: Ver bien este


ejemplo en hoja 14, no lo pas
todo porque est medio raro

^nos permite abstraer el elemento del universo del diseo y devuelve el trmino lgico
al que representa.
^ = se explica con (sec)
Cuando un parmetro se pasa como in/out tengo que decir en la pre que en el estado
inicial ese parmetro vale algo ^p = p0
La definicin de la representacin de un mdulo de diseo implica tomar en cuenta todo
aspecto referido a cmo se satisfacen los requerimientos declarados en la interfaz:
Estructura: describe la estructura interna sobre la cual las operaciones se aplican.
Relacin entre la representacin y la abstraccin: Por un lado expone toda restriccin
sobre la estructura de representacin a fin de que efectivamente pueda ser considerada una
implementacin de un valor del tipo al que implementa; y por otro vincula los valores con
su contraparte abstracta, es decir, con algn trmino de la especificacin a quien este
represente.
Algoritmos: eso mismo, la programacin en pseudo-cdigo de las operaciones, tanto las
exportadas como las auxiliares, y para todos ellos incluye el clculo detallado que justifica
su complejidad.
Servicios usados: declara toda demanda de complejidad, aliasing o efecto colateral que los
servicios usados de otros tipos en la programacin de los algoritmos deban satisfacer
La estructura de representacin describe los valores sobre los cuales se representar el
gnero que se est implementando.
Esta tiene que tener en cuenta la posibilidad, no solo de ser capaz de representar todos los
trminos del gnero de la especificacin sino tambin que las operaciones sean
implementables de acuerdo a las exigencias del contexto de uso.
Ejemplo:
conjuntoDeNat se representa con <secuenciaDeNat, Nat>
esta tupla vive en el mundo de la implementacin
Todos los conjuntos de naturales pueden representarse con secuencias de naturales el nat en
este caso tiene que ver con que se haba pedido el mnimo en O(1)
Invariante de representacin
Nos ayuda en la tarea de filtrar toda aquella estructura que no resulta implementar un
trmino de la especificacin. Expresa de alguna forma un predicado de sanidad de la
estructura (por ejemplo, la secuencia no debe contener nmeros repetidos, y no debe
contener valores menores al mnimo).
El tema de no tener repetidos en este caso tena que ver tambin con un orden de
complejidad pedido.
Rep: bool
En el ejemplo del conjunto creamos la operacin SinRepetidos que no es relevante en la
implementacin si no ?
Si pidiera por ejemplo que se representara con secuencias ordenadas, sera posible que
existieran secus no ordenadas que pertenezcan al TAD pero no las puedo representar.
SinRepetidos es del mundo de los TADs y hay que axiomatizarla como funcin
auxiliar

El sentido que se le otorga al invariante de representacin es que cada operacin requiere


para su ejecucin que el invariante de representacin valga sobre las estructuras pasadas
como parmetro y si esto no se cumple, entonces esta asegura que tambin vale finalizar la
ejecucin. Esta presente en forma implcita en la pre y la post de todas las operaciones
exportadas.
En una operacin el estado intermedio del parmetro no es visible para quien utiliza
la aplicacin. Ac puede ser que no valga el invariante, pero tengo que restaurarlo al
final. Debe valer en la pre y en la pos (no importa lo que pase en el medio).
La funcin de abstraccin es una herramienta que permite vincular una estructura con
algn valor abstracto al que representa. La manera en la que se caracteriza un trmino es o
bien a travs de los generadores o de los observadores. Normalmente el uso de los
observadores resulta ms sencillo.
Se puede hacer a travs de los generadores pero puede traer problemas de
recursiones infinitas. Mejor hacerlo a partir de los observadores
Dada una estructura que satisface el invariante de representacin me devuelve algn
conjunto abstracto que est siendo representado por esa estructura.

t =obs t
conj[nat]

C
Conjdenat

^ sec

Interfaz
SRC
Representacin

abs

<SecuNat, Nat>

<secu[nat], nat>

<s,n>
<[1,2,3],1> {1} U ({2} U ({3} U vacio)
2, 3, 1
<[1,3,2], 1> 1 3 2
El comportamiento de la funcin de abstraccin tiene sentido cuando ?
Se caracteriza a partir de los observadores bsicos. La funcin de abstraccin tiene que
caracterizar el valor que tienen los observadores bsicos sobre la instancia abstracta que
estoy caracterizando en funcin de la estructura.
Es una estructura vlida porque satisface mi invariante de representacin (rep)
El tringulo conmuta, esto permite probar que la manera en que se implement el
algoritmo modifica las estructuras respetando la igualdad observacional.

Comentario: Vaya uno a saber.

Top Down: De los tipos ms grandes a los ms chicos. A partir del ms grande armo la
estructura de las cosas necesarias. Desde los que se usan hacia los que son usados.
Top-down (de arriba abajo) y bottom-up (de abajo arriba) son estrategias de procesamiento de informacin
caractersticas de las ciencias de la informacin, especialmente en lo relativo al software. Por extensin se aplican
tambin a otras ciencias sociales y exactas.
En el modelo top-down se formula un resumen del sistema, sin especificar detalles. Cada parte del sistema se refina
diseando con mayor detalle. Cada parte nueva es entonces redefinida, cada vez con mayor detalle, hasta que la
especificacin completa es lo suficientemente detallada para validar el modelo. El modelo top-down se disea con
frecuencia con la ayuda de "cajas negras" que hacen ms fcil cumplir requisitos aunque estas cajas negras no
expliquen en detalle los componentes individuales.
En contraste, en el diseo bottom-up las partes individuales se disean con detalle y luego se enlazan para formar
componentes ms grandes, que a su vez se enlazan hasta que se forma el sistema completo. Las estrategias
basadas en el flujo de informacin "bottom-up" se antojan potencialmente necesarias y suficientes porque se basan
en el conocimiento de todas las variables que pueden afectar los elementos del sistema.
Los mtodos top-down fueron favorecidos en la ingeniera de software hasta que lleg la programacin orientada a
objetos a finales de los 1980s.
El enfoque top-down enfatiza la planificacin y conocimiento completo del sistema. Se entiende que la codificacin
no puede comenzar hasta que no se haya alcanzado un nivel de detalle suficiente, al menos en alguna parte del
sistema. Esto retrasa las pruebas de las unidades funcionales del sistema hasta que gran parte del diseo se ha
completado.
Bottom-up hace nfasis en la programacin y pruebas tempranas, que pueden comenzar tan pronto se ha
especificado el primer mdulo. Este enfoque tiene el riesgo de programar cosas sin saber como se van a conectar al
resto del sistema, y esta conexin puede no ser tan fcil como se crey al comienzo. La reutilizacin del cdigo es
uno de los mayores beneficios del enfoque bottom-up.
El desarrollo de software moderno usualmente combina tanto top-down como bottom-up. Aunque un conocimiento
completo del sistema se considera usualmente necesario para un buen diseo, haciendo que tericamente sea un
enfoque top-down, la mayora de proyectos de desarrollo de software tratan de usar cdigo existente en algn grado.
El uso de mdulos existentes le dan al diseo un sabor bottom-up. Algunos enfoques usan un enfoque en el que un
sistema parcialmente funcional es diseado y programado completamente, y este sistema se va expandiendo para
llenar los requisitos del proyecto.

Algoritmos:
Servicios usados: operaciones de otros mdulos que fueron utilizadas y requerimientos
sobre estas (complejidad, efectos colaterales, modificacin de argumentos)
Algunas otras notas: la asignacin por lo general cuando es un tipo bsico copia y
cuando no, da una referencia. Aliasing crear un nuevo nombre para la misma cosa.
Rep es interno. Se escribe para establecer relaciones concretas entre todas las
componentes de la estructura
ABS: externo. Lo escribimos porque dice cmo se relaciona todo lo que hicimos con
el lenguaje comn (tad)

Comentario: Ver si se puede


completar con algo
Comentario: Esto lo chamull
yo no lo deca en ningn lado

La relacin TAD <-> modulo no es 1 a 1, distintos mdulos pueden explicarse con un


tad y se puede hacer un mdulo de solo una parte de un tad. Ms difcil es que un
mdulo se explique con varios tads, pero es posible.
Hablando de un ejemplo: poner en Sacar() que un elemento no tiene que estar, es
subimplementar el conjunto, y si bien es vlido hay que saber por qu lo estamos
haciendo y aclararlo (tal vez no queremos que funcione para algunas instancias)
La notacin ^toma las estructura del diseo y habla del tad que representa. El rep va
en el mundo de los tads, no del diseo.
Cuando voy a hacer el abs debo verificar que la estructura cumpla el rep.
Las cosas las diferencio con la igualdad observacional, entonces voy a mostrar cmo
defino los observadores a travs de la estructura interna
La axiomatizacin tiene que ser clara, no tiene por qu ser eficiente
a0 = a no es una pre, pero lo voy a usar despus, es una etiqueta de estado
En las pos, inout siempre tengo que decir si lo cambi o no. El out tengo que decir
qu asign en caso de que valga la pre. In no se toca
El TAD es el qu? Y el diseo el cmo? (que se explica con el tad). El tad es el
gnero funcional y el diseo es el genero imperativo.
Los mdulos de abstraccin tienen tambin servicios exportados.
Encapsulamiento:
Publico:
- Interfaz: operaciones (cmo se llaman, qu reciben, qu devuelven, pre, pos y
condicin de cada una, complejidad, aspectos de aliasing, descripcin breve del
mdulo (generos, operaciones))
- Se explica con (cual tad) y el TAD completo.
La operacin es imperativa, pero la pre y la pos son funcionales
Privado:
- Estructura de representacin
- Rep y Abs
- Algoritmos
- Servicios usados: se necesita un mdulo x con operaciones y y complejidad z
Iteradores: El tad iterador me dice qu es y qu hace. Secuencia subyacente: un
iterador me permite recorrer los elementos de una coleccin de una manera
linealizada.
Aliasing: es una cosa con ms de un nombre. El principal error es olvidarse que lo
hicimos. Cuando hago una asignacin de un tipo que no es bsico hay aliasing (a no
ser que explcitamente lo copie y cree la funcin: puedo hacer shallow copy, por
ejemplo de una secuencia, copio la estructura pero apunto a los mismos elementos,
las secuencias son dependientes. O puedo hacer deep copy, copio tambin los
elementos. (VER GRAFICO LINDO EN HOJAS PRACTICA)

Si devuelvo algo por referencia, aviso que si lo modifica, se modifica tambin lo de


adentro.
Si quiero hacer un puntero a un nodo (en una estructura) rompo el encapsulamiento.
Puede tener una lista indexada, iterador de la lista, puntero al elemento en s (pero
no al nodo)
El iterador puede ser un puntero al nodo porque forma parte del mdulo de la lista
(es una manera de encapsular el puntero a nodo)

RBOLES DE BSQUEDA
Alternativas de diseo para diccionarios y conjuntos (son parecidos, as que trabajaremos
sobre diccionario que es ms genrico).
Diccionario: Agregar, borrar, pertenece, la nica diferencia con el conjunto es que
obtener me devuelve una definicin. Podra pensarlo como un conjunto de tuplas.
ABM o ABMC
* Altas: definir una clave en el diccionario
* Bajas: borrado.
* Modificaciones: Que puede traducirse en baja+alta
* Consultas: Definido? y obtener (ver si est un elemento o consultar su significado).
Si trabajamos con listas y arreglos tenemos una disyuntiva:
* Arreglo ordenado: Bsqueda: O(log n). Insercin/borrado: O(n)
* Arreglo no ordenado, listas: Bsqueda O(n). Insercin/Borrado: O(1)
La alternativa es trabajar con rboles binarios.
Podemos imaginar al ab representado con punteros, uno al hijo de la izquierda y otro al de
la derecha.
Trabajar con ab nos permite hacer bin() en O(1) pero buscar nos toma O(n).
La idea es ser cuidadosos con la forma que le damos al rbol de modo que al buscar
sepamos para qu lado ir.
rbol Binario de Bsqueda (ABB):
Es un rbol binario con la propiedad de que, para todo nodo, los valores de los elementos
en su subrbol izquierdo son menores que el valor del nodo, y los valores de los elementos
de su subrbol derecho son mayores que el nodo.
Dicho de otra forma: el valor de todos los elementos del subrbol izquierdo es menor que el
valor de la raz, y el valor de todos los elementos del subrbol derecho es mayor que el
valor de la raz.
Adems tanto el subrbol izquierdo como el derecho son tambin ABB.

Invariante de representacin:
EsABB?: ab() bool (rep)
EsABB? (a) nil?(a) L
c: , est?(c, izq(a)) sii c < clave(raz(a))
c: , est?(c, der(a)) sii c > clave(raz(a))
EsABB?(izq(a))
EsABB?(der(a))
Todo elemento del subrbol debe ser mayor o menor respectivamente, no alcanza con
que solo lo sea la raz.
Un rbol degenerado a derecha tambin puede ser un ABB si es cierto que en cada nodo
los elementos que estn a la derecha son mayores que la raz.
Sin hacer grandes modificaciones puedo agregar ordenado.
Para la bsqueda recorremos el rbol desde la raz y en cada paso decidimos si vamos a la
izquierda o a la derecha (segn el elemento que estamos buscando sea mayor o menor al
valor del nodo).
Para definir vamos bajando por el rbol hasta llegar a un padre al que le falta un hijo (hacia
el lado al que deberamos insertarlo segn sea mayor o menor).
En la interfaz la funcin se llama definir. Al escribir el algoritmo, la funcin que toma
un rbol se corresponda con la que haba definido en la interfaz: iDefinir
(representacin del mdulo).
La complejidad es la de la altura del rbol, ya que la acota la distancia entre el nodo y la
hoja ms lejana.
Con los ABB entonces:
Insercin: depende de la distancia del nodo a la raz, en el peor caso O(n), en el caso
promedio (si supongo una distribucin uniforme de las claves) sera O(log n).
Y lo mismo vale para la bsqueda.
Borrado:
Se contemplan tres casos posibles:
- el elemento a borrar es una hoja
- el elemento a borrar tiene un solo hijo
- el elemento a borrar tiene dos hijos
El algoritmo bsico es muy sencillo: buscamos al padre y eliminamos la hoja. Ojo! No hay
forma de retroceder en la bsqueda.

Si el elemento tiene un nico hijo h, buscamos al padre y reemplazamos la conexin p->e


por la conexin p->h (si e fuera la raz, lo reemplazamos por h).
Si el elemento tiene dos hijos podemos pensar que tiene un predecesor, que es el mximo
elemento menor que e, y sera su antecesor si hicisemos un inorder del rbol.
Llamemos p al predecesor. Este no puede tener dos hijos, porque si no, no sera el
predecesor inmediato.
Llamemos h a su nico hijo.
P es el candidato perfecto para poner en el lugar de e, por lo que ponemos su contenido ah.
Ahora el lugar de p es o bien una hoja, o bien tiene un nico hijo (h) y para borrarlo
estamos en alguno de los casos anteriores.
Se podra hacer lo mismo en base al sucesor (es decir el mnimo elemento mayor que e)
Es decir, buscamos el mximo elemento menor que e en su subrbol izquierdo, o el
mnimo elemento mayor que e en su subrbol derecho.
Los nodos internos son aquellos que no son ni raz ni hojas. EL borrado de un nodo interno
requiere encontrar al nodo que hay que borrar y a su predecesor inmediato. En el caso peor
ambos costos son lineales: O(n) + O(n) = O(n)
Como conclusin, los ABB funcionan razonablemente bien en el caso promedio pero no
dan garantas. En el peor caso (y nada impide caer en l) sigue siendo lineal.
En este sentido, los arreglos tambin son lineales en el peor caso y ocupan menos memoria
(no hay que guardar punteros).
Como vimos, en el peor caso todos los algoritmos tienen un costo lineal que en detalle sera
O(h) siendo h la altura del rbol.
Si distribuyeramos los nodos de manera pareja de manera tal que el rbol tuviese la
mnima altura y estuviese siempre parejo qu altura tendra?
Teorema: un rbol binario perfectamente balanceado de n nodos tiene altura log2 n + 1
Supongamos que cada nodo tiene 0 o 2 hijos.
Llamemos ni a la cantidad de nodos internos (ms la raz) y nh a la cantidad de hojas.
Propiedad: si n>1, nh = ni + 1
Demostracin:
CB: trivial.
Suponemos que vale para nh y ni y agregamos un nivel. Las hojas se duplican (nh = 2nh) y
los nodos internos crecen en tantos como antes tena hojas:
Ni = ni + nh = (nh -1) + nh = 2 nh 1 = nh 1
Corolario: al menos la mitad de los nodos son hojas.
Teorema: un rbol binario perfectamente balanceado de n nodos tiene altura |log2 n| + 1
Demo (esquema):
Sabemos que (1) n = ni + nh (1) y (prop) si n > 1, nh = ni + 1.

Imaginemos que podamos las hojas: nos queda un rbol con las mismas propiedades, 1
menos de altura (llammosla h), la mitad de los nodos y ahora todas las ramas de la misma
longitud. Cuntas veces ms podemos podarlo?
Lo podemos pensar al revs: cuntos niveles se pueden agregar desde el comienzo para
tener un rbol de altura h?
Al agregar un nivel la cantidad de nodos se duplica, porque nh = ni + 1, pero ni = n,
entonces nh = n + 1. Reemplazando en (1) nos queda que n = n + (n + 1) + 1.
Entonces n = 1. 2.2 = 2h = 2 log2 n (porque multiplico por 2 h veces).
Por ende h = log2 n y la altura del rbol era h + 1.
Detalles de la demo, en el libro.
Nota: este resultado es generalizable a rboles k-arios
Si tuvisemos rboles perfectamente balanceados todas nuestras operaciones seran O (log
n)
Pero es muy costoso mantener el balanceo perfecto. Sin embargo, podemos tener un
balanceo casi perfecto, haciendo que todas las ramas tengan casi la misma longitud.
casi interpretado como: la longitud entre dos ramas cualesquiera de un nodo difiere a lo
sumo en 1.
Nuestros algoritmos debern garantizar que sucesiones de inserciones y/o borrados no
destruyan ese balance (o lo reestablezcan).
AVL (Adelson-Velskii & Landis)
Son rboles casi perfectamente balanceados.
Resulta mejor tener algo controladamente desordenado que tenerlo perfectamente
ordenado.
Un rbol se dice balanceado en altura si las alturas de los subrboles izquierdo y derecho de
cada nodo difieren a lo sumo en una unidad.
Para cada nodo se calcula el factor de balanceo FdB = altura del subrbol derecho altura
del subrbol izquierdo.
En un AVL, para todo n: nodo |FdB(n)| < 1
El factor de balanceo se calcula en cada nodo y se almacena junto con l.
El pero AVL (el ms desbalanceado) es el rbol de fibonacci.
Agarramos dos rboles y los concatenamos con una nueva raz, de modo que no hay
nuevas hojas y las hojas del nuevo equivalen a la suma de las hojas de los dos anteriores.
Tenemos el rbol Ph con altura h, P0 el rbol vaco y P1 tiene un solo nodo. Para h >1, Ph
tiene una raz y dos subrboles: Ph-1 y Ph-2
La cantidad de hojas sera la sucesin de fibonacci fh = f h-1 + f h-2
La cantidad de nodos es los nodos internos + las hojas, Ph tiene fh + algo
Como fh crece exponencialmente con h, eso significa que la altura de Ph que es h crece
logartmicamente con la cantidad de nodos de Ph
Este es el peor AVL posible, y an as su altura es logartmica en n.

Comentario: Con tiempo buscar


demostracin de esto

De hecho Adelson-Velskii & Landis demostraron que un rbol de fibonacci con n nodos
tiene altura menor a 1,44 log2 (n+2) 0,328.
Por ende un AVL con n nodos tiene altura (log n)
rbol de Fibonacci

rboles de Fibonacci de orden 1, 2, 3 y 4.

Se llama rbol de Fibonacci a una variante de rbol binario con la propiedad que el orden de
un nodo se calcula como la sucesin de Fibonacci.
El rbol de Fibonacci se define de la siguiente manera:
El rbol nulo (no contiene ningn nodo) es de orden 0.
El rbol que consta de un nico nodo es de orden 1.
Para n > 1, el rbol de Fibonacci de orden n consta de un nodo raz con el rbol de Fibonacci
de orden n-1 como hijo izquierdo y el rbol de Fibonacci de orden n-2 como hijo derecho.
Dado que este tipo de rbol es un caso particular de un rbol AVL, ya que el factor de
equilibrio de todo nodo es -1, un rbol de Fibonacci es balanceado con altura O(log n).
En matemticas, la sucesin de Fibonacci (a veces mal llamada serie de Fibonacci) es la
siguiente sucesin infinita de nmeros naturales:
La sucesin comienza con los nmeros 1 y 1,1 y a partir de estos, cada trmino es la suma de los dos anteriores,
es la relacin de recurrencia que la define.

Definicin recursiva[editar]
Los nmeros de Fibonacci quedan definidos por la ecuacin:
(3)
partiendo de dos primeros valores predeterminados:

se obtienen los siguientes nmeros:


para
Esta manera de definir, de hecho considerada algortmica, es usual en Matemtica discreta.

Continuando con AVLs


Con esta estructura, las bsquedas toman O(log n).
Para la insercin y el borrado debemos garantizar que los algoritmos restauren el invariante
del AVL.
Insercin: Insertamos el nuevo nodo como una hoja, como en el ABB, y luego
recalculamos los factores de balanceo que cambiaron por la insercin, solo en la rama en la
que ocurri la insercin, de abajo hacia arriba, ya que no podran haber cambiado otros
factores.
Si en la rama aparece un factor de balanceo de +-2 hay que rebalancear. Esto se hace a
travs de rotaciones.
Rotaciones en AVL
Hay 4 rotaciones posibles, dos simples y dos dobles:
- RR: insercin en el subrbol derecho R en un hijo derecho R del nodo que se desbalancea.
- LR: insercin en el subrbol izquierdo L en un hijo derecho R del nodo que se
desbalancea.
- LL: insercin en el subrbol izquierdo L en un hijo izquierdo L del nodo que se
desbalancea.
- RL: insercin en el subrbol derecho R en un hijo izquierdo L del nodo que se
desbalancea.
Ejemplo RR (LL es simtrica).

Encontramos el primer nodo de la rama donde cambi el factor de balanceo, en este caso Q.
La insercin no influye en los antepasados de P porque luego de la rotacin recuperan su
factor de balanceo anterior.

La complejidad fue O(1) porque solo reacomodamos punteros. Vamos volviendo a la


raz reacomodando todos los factores de balanceo (en el peor de los casos), hasta que
para algn padre no cambie el FdB.
Una vez que hago una rotacin, ya est.
Ejemplo LR (la RL es simtrica)

Lo que tenemos que hacer es:

La insercin no influye en la altura de los antepasados de P por lo que no hace falta seguir
rebalanceando.
Al padre de P le cambiamos el hijo por R pero ambos tenan altura h+1+1 entonces ya
no cambia.
Si el factor de balanceo de R es del mismo signo alcanza con una rotacin simple, si el
signo es distinto entonces tengo una rotacin doble.
Las rotaciones cuestan O(1) pero tengo que encontrar dnde hacerlas, y encontrarlo toma
O(h) = O(log n).
Entonces el costo de la insercin sera:
1) Insertar el nodo: proporcional a la altura del rbol (log n)
2) Recalcular los FdB de la rama: proporcional a la altura del rbol (log n)
3) Hacer las rotaciones necesarias: O(1) ya que se hacen una o dos rotaciones por insercin.
TOTAL: (log n)

Borrado:
Borramos el nodo como en un ABB, recalculamos los FdB que cambian por el borrado
(solo en la rama del borrado, de abajo hacia arriba).
Para cada nodo con FdB +-2 hay que hacer una rotacin simple o doble: O(log n)
rotaciones en el peor caso.
Al borrar puedo tener que rotar ms de una vez y hay que seguir chequeando
Eliminemos una hoja de un subrbol izquierdo de P, si el hijo derecho tiene FdB +1

Eliminemos una hoja de un subrbol izquierdo de P, si el hijo derecho tiene FdB 0

Eliminemos una hoja de un subrbol izquierdo de P, si el hijo derecho tiene FdB -1 y su


nieto tambin

Hacemos una rotacin entre R y Q (P pasa a +2, R y Q pasan a +1) y luego una rotacin PR.
Eliminemos una hoja de un subrbol izquierdo de P, si el hijo derecho tiene FdB -1 y su
nieto +1

Hacemos una rotacin entre R y Q (P y R pasan a +2, Q pasa a 0) y luego una rotacin P-R.
Entonces el costo del borrado sera:
1) Borrar el nodo: proporcional a la altura del rbol (log n)
2) Recalcular los FdB de la rama: proporcional a la altura del rbol (log n)
3) Hacer las rotaciones necesarias: (log n) * (1) ya que en el peor caso hay rotaciones a
lo largo de toda la rama.
TOTAL: (log n)
Tarea:
Mirar en detalles las rotaciones, entenderlas y ser capaces de explicarlas.
Escribir el pseudo cdigo imperativo de la insercin en AVL y del borrado
TABLAS DE HASH
Queremos buscar/obtener en O(1).
No siempre se puede pero bastantes veces s.
Para algunos tipos particulares de diccionario es fcil, por ejemplo si las claves son nat en
un rango k n+k.
Agarro un arreglo de n posiciones, pongo las definiciones y puedo buscar en O(1).
Y si el rango es muy grande pero ralo?
No tiene sentido hacer un arreglo de 65 millones para guardar 40 DNIs por ejemplo.
Si relajamos algunos requerimientos podemos empezar a obtener resultados interesantes.
Vamos a conformarnos con tener O(1) en el caso esperado sabiendo que podra haber casos
peores.
Supongamos que queremos almacenar n elementos, cuyas claves son valores numricos de
1..N con N >> n. (Por ejemplo 100 DNIs y el significado () son todos los datos de la
persona).
En lugar de tener un arreglo A[1..N] de vamos a tener un arreglo A[1n] de conj< >. Y
adems una funcin h: DNI [0n-1]
Por ejemplo h(d) = d mod 100.
Los datos del DNI d estn en A[h(d)], pero puede que no sean los nicos.

Esta es la idea bsica de la tabla de hash.


H es la funcin de hash/hashing
Si la clave no es numrica alcanza con encontrar una funcin total de [0..n-1]
Entonces: Una tabla de hash es una tupla <A,h>, donde A es un arreglo de k posiciones y h
la funcin de hash que va de en [0k-1].
La estructura de datos est compuesta por ambas cosas, si cambia h cambia tambin la
tabla.
El invariante y la funcin de abstraccin cambian dependiendo del h en particular.
Cada posicin del arreglo se suele llamar bucket. Si h distribuye bien a las claves
tendremos un caso esperado de O(1).
El peor caso ser bastante mayor y depender de cmo resolvamos las colisiones.
El AVL nunca me da mejor que orden logartmico, pero tampoco me da peor. En este
caso puedo tener O(1) pero tambin puedo llegar a tener O(n).
Se dice que una funcin de hash es perfecta si c1,c2 perteneciente a , h(c1) es distinto
de h(c2). Para eso necesitamos k > ||, lo que muy raras veces sucede.
De hecho suele suceder que || >> k. Por ende, es muy probable (ms de lo que uno se
imagina) que h(c1) = h(c2). Es decir que c1 y c2 colisionen.
Ejercicio: proponer una funcin de hash perfecta para el caso en que las claves sean strings
de largo 3 en el alfabeto {a,b,c}
H puede no ser mala pero tener malos casos en momentos concretos.
Supongamos que conocemos la distribucin de frecuencias de y llamamos P(c) a la
probabilidad de la clave c. Nos gustara que
i perteneciente a [0k-1], la sumatoria de los c tales que h(c) sea i de los P(c) sea aprox
1/k
Es decir, me fijo todas las claves que hashean a la misma celda y busco que para todas
la probabilidad sea 1/k (con k = longitud del arreglo).
Es decir, que para cada posicin del arreglo, la probabilidad de que alguna clave vaya a
parar ah sea aproximadamente uniforme. Esto se llama uniformidad simple y es muy difcil
de lograr. En gran parte porque P suele ser desconocida.
A modo de ejemplo, pensemos en A[05] y h(c) = c mod 5. Dos conjuntos de datos muy
similares {1,7,10,14} vs {1,6,11,16}, en el primer caso ocupan las posiciones 1,2,0 y 4 y en
el segundo quedan todos en la 1.
Como conocer las distribuciones es muy difcil, lo que se busca en la prctica es tener
independencia de la distribucin de los datos. Y adems, saber que las colisiones son
prcticamente inevitables y habr que lidiar con ellas s o s.

Comentario: Para pasar esto ver


Diago 8 Tablas de Hash 1)

Paradoja del cumpleaos: si elegimos 23 personas al azar, la probabilidad de que dos de


ellas cumplan aos el mismo da es mayor a (aprox. 50,7%). Es decir que an
suponiendo distribucin uniforme de los nacimientos, hay alta probabilidad de festejo
conjunto.
Tarea: pensar en la demo: cuantos pares distintos se pueden generar?
Corolario: si tenemos una tabla con k = 365 y h distribuye uniformemente entre ellas, an
as tenemos probabilidad mayor a de que luego de 23 inserciones se produzca una
colisin.
Dado que las colisiones sin inevitables, una buena tabla de hash tiene que poder lidiar con
ellas.
Dos familias de mtodos:
* Hashing (o direccionamiento) abierto: los elementos se guardan en la tabla.
* Hashing (o direccionamiento) cerrado: en cada A[i] hay algn tipo de contenedor que
almacena todos los elementos que son hasheados a i.
(Ojo! La bibliografa a veces alterna los nombres y las definiciones, lo que importa es la
idea ms que el nombre).
Tenemos varias alternativas para el contenedor a usar en un hashing cerrado. Por ejemplo,
podran ser AVLs, pero perderamos el ansiado O(1).
Podran ser listas, podemos tener una lista que permita agregar el elemento (insercin) en
O(1). La bsqueda y borrado sera lineal en la cantidad de elementos del bucket.
Cunto pueden medir estas listas?
Factor de carga:
Lo definimos como fc = n/k. Es decir, la relacin entre la cantidad de elementos presentes y
el tamao de la tabla.
Teorema: Suponiendo que h es simplemente uniforme y se usa hashing cerrado por
concatenacin, en promedio:
- Una bsqueda fallida requiere (1+fc) y una bsqueda exitosa requiere (1+ fc/2)
Corolario: si n <=k o incluso si n ~ k tenemos O(1)
Por ende es muy importante dimensionar bien la tabla.
Si n no excediera k entonces sera prcticamente 1 y si es el doble?. Si n tiende a
infinito, n/k tiende a n, entonces es n
Hashing abierto: La idea es que ante una colisin vamos a ubicar el elemento en otra celda
de la tabla que est libre.
Los mtodos varan segn cmo hacen para encontrar esa otra posicin.
La funcin de hash incorpora como segundo parmetro al nmero de intento: El i-simo
intento para c se corresponde con h(c,i).
En hashing abierto el borrado suele ser problemtico.
Algoritmos de Hashing abierto:
Insercin de clave c en A:

1
2
3
4

i=0
mientras (i < |A| A[h(c,i)] est ocupada) incrementar i
si (i <|A|), el elemento va en A[h(c,i)]
si no, overflow!

Bsqueda de clave c en A:
1
i=0
2
incrementar i mientras:
* i< |A|
* A[h(c,i)] distinto de null
* A[h(c,i)]. clave distinto de c
3
si (i < |A|) A[h(c,i)] distinto de null return A[h(c,i)].valor
4
si no, no est
Borrado: Si marcamos como null al borrar, puede que si buscamos luego un elemento que
hasheo al espacio siguiente porque este estaba ocupado, ya no lo encontremos (porque la
bsqueda nos dice que si el espacio es null no est). Es mejor marcarlos como borrados,
aunque empeora la performance de la bsqueda para el caso exitoso por qu?
Tengo que asegurarme de que h me brinda tantas posibilidades distintas, al menos como
la cantidad de posiciones del arreglo.
En un sistema de tiempo real est prohibidsimo usar tablas de hash porque puedo
tener O(n) y alguna operacin puede tardar ms.
Puede que no tenga datos de contexto pero sea bueno utilizar una funcin de hash: por
ejemplo, porque estoy en lenguajes bsicos que no tienen punteros y quiero algo mejor
que un arreglo.
H(c,i) es entonces la funcin que nos indica en qu posicin de A debemos intentar ubicar
la clave c en el intento i. No tiene sentido que esta funcin deje posiciones de la tabla sin
explorar por lo que se habla de barrido:
Barrido lineal: La idea es ir recorriendo todas las posiciones de la secuencia:
h(c.i) = (h(c)+i) mod |A|, donde h(c) es otra funcin de hashing.
La secuencia que se genera es A[h(c)], A[h(c)+1],, A[|A|], A[0],
Ejemplo: h(c,i) = (h(c)+i) mod 101, h(c) = c mod 101.
Insertemos 2, 103, 104, 105, etc... en ese orden.
Cada insercin colisiona varias veces antes de poderse realizar. Esto se llama
aglomeracin primaria, y si bien es un caso extremo, puede darse.
Cuando hay aglomeracin primaria, si dos secuencias colisionan en algn momento,
siguen colisionando.
Barrido cuadrtico:
h(c.i) = (h(c)+ a i + b i2) mod |A|, donde h(c) es una funcin de hash y a y b son
constantes.

Comentario: Y esto lo
charlamos?

Es una forma de evitar la aglomeracin primaria, ya que el polinomio vara dependiendo


del nmero de intento.
Sin embargo puede producirse aglomeracin secundaria: si hay una colisin en el primer
intento, sigue habiendo colisiones. (h(c1) = h(c2) => h(c1, i) = h(c2, i) )
Es muy poco probable que dos secuencias de insercin coincidan al principio pero si
coinciden van a coincidir siempre.
Hashing doble o rehashing:
La idea es que el barrido dependa tambin de la clave.
h(c,i) = (h1(c)+i h2(c)) mod |A|, donde h1(c) y h2(c) son dos funcines de hashing.
Qu pasa con la aglomeracin primaria y la secundaria?
Es la probabilidad de que la primera coincida y la segunda coincida. La multiplicacin
de dos probabilidades tiende a disminuir. Las funciones tienen que ser independientes
(es lo que se busca).
El hashing doble es muy poco probable que tenga aglomeracin primaria y reduce los
fenmenos de aglomeracin secundaria.
Si las claves no son naturales, para construir buenas funciones de hash, la idea general es
asociar cada clave a un nmero entero, en una forma que depender del contexto. Por
ejemplo el codo ASCII de cada carcter, multiplicado por cierta base elevada a la posicin:
ascii(prim(s)) . 20 + ascii(prim(resto(s))) . 21 + ....
Se puede hacer en base 2 o en cualquier otra base.
Una vez que las claves son numricas hay varias alternativas que varan en complejidad y
en comportamiento con respecto a la aglomeracin para terminar de definir la funcin.
Basadas en divisin:
h(c) = c mod |A| tiene baja complejidad, pero si |A| = 10p para algn p , todas las claves
cuyos ltimos dgitos coincidan colisionaran.
Y si |A| = 2p para algn p, lo mismo suceder con los p bits menos significativos.
En general la funcin de hash debera depender de todas las cifras de la clave, cualquiera
sea la representacin.
Una buena eleccin en la prctica: un nmero primo no demasiado cercano a una potencia
de 2 (por ejemplo h(c) = c mod 701 para |A| = 2048 valores posibles)
No suele ser buena idea que la funcin de hash dependa solo de algunos dgitos.
Hay que tratar de que el tamao de la tabla no sea potencia de 2, ni de nadie (tratar de
buscar nmeros primos.
Bits ms y menos significativos

Un conjunto de bits, como por ejemplo un byte, representa un conjunto de elementos ordenados. Se llama bit ms
significativo (MSB) al bit que tiene un mayor peso (mayor valor) dentro del conjunto, anlogamente, se llama bit
menos significativo (LSB) al bit que tiene un menor peso dentro del conjunto.
En un Byte, el bit ms significativo es el de la posicin 7, y el menos significativo es el de la posicin 0
+---+---+---+---+---+---+---+---+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Posicin del bit
+---+---+---+---+---+---+---+---+
|128|64 |32 |16 | 8 | 4 | 2 | 1 | Valor del bit de acuerdo a su posicin
+---+---+---+---+---+---+---+---+
Bit ms significativo

Bit menos significativo

En una palabra de 16 bits, el bit ms significativo es el de la posicin 15 y el menos significativo el de la posicin 0.


Tomemos, por ejemplo, el nmero decimal 27 codificado en forma binaria en un octeto:
-> 0 0 0 1 1 0 1 1
Aqu, el primer '0', el de la izquierda, (que se corresponde con el coeficiente de

), es el bit ms significativo,

siendo el ltimo '1', el de la derecha, (que se corresponde con el coeficiente de

), el menos significativo.

En cualquier caso, el bit ms significativo es el del extremo izquierdo y el menos significativo el del extremo derecho.
Esto es anlogo al sistema decimal, en donde el dgito ms significativo es el de la izquierda y el menos significativo
el de la derecha, como por ejemplo, en el nmero 179, el dgito ms significativo, el que tiene mayor valor, es el 1,
(el de las centenas), y el menos significativo, el 9, (el de las unidades).
Este concepto de significatividad se extiende al conjunto de bytes que representan nmeros o valores numricos
12

Byte (B)
(pronunciada [bait] o ['bi.te]) es una unidad de informacin utilizada como un mltiplo del bit.
Generalmente equivale a 8 bits

Particin y extraccin:
Pueden ser tiles cuando la clave es muy larga, la idea es pensar a c como compuesto por
segmentos c1, c2, , cn
En el caso de particin se busca calcular: h(c) = h(c1, c2, , cn)
Ejemplo, a partir del nmero de la tarjeta de crdito en cuatro partes y luego hacer (c1 + c2
+ c3 + c4) mod 701.
En el caso de extraccin, la idea es quedarse solo con algunos de los ci.
Entonces hay que tratar de que las funciones de hash no sean lineales y hacerlas lo ms
complejas posible, siempre que garantice que recorra toda la tabla.
Las funciones de hash tienen inters ms all del mundo de las estructuras de datos. Se usan
mucho en seguridad. En cripto se utilizan hashes de una va, es decir, la idea es que sea
prcticamente imposible obtener la preimagen.
Se suele pedir que cumplan con:
* Resistencia a la preimagen: dado h debera ser difcil encontrar un m tal que h =
hash(m).
* Resistencia a la segunda preimagen: dado m1 debera ser difcil encontrar un m2
distinto de m1 tal que hash(m1) = hash(m2).
Etc
Son muy tiles para almacenar contraseas (se encriptan en las bases de datos), ya que
conviene que no se puedan leer, y para asegurar que el software bajado es el correcto.

NOTA: chusmear http://es.wikipedia.org/wiki/MD5 MD5 y SHA-1


FALTO PASAR EL BONUS Y UNIVERSAL HASHING (3 ltimas diapos de Teorica
2 de Hashing que en realidad son extras)
BUSQUEDA DIGITAL, TRIES, ETC.
Motivacin:
Queremos que el tiempo sea menos dependiente de la cantidad de claves.
Rendimiento razonable en el peor caso
Rpidos en la prctica
Adecuados para claves de tamao variable
Adecuados para otro tipo de aplicaciones (por ejemplo pattern matching, indexacin, en
general text retrieval, compresin de textos)
Pattern Matching es el concepto asociado al chequeo estructural de un dato respecto de una estructura esperada.

Hacemos anlisis asinttico en el peor de los casos (en funcin del tamao del input).
No se puede buscar en un tiempo menor que log n con ningn algoritmo.
Si tengo un conjunto de n cosas necesito log n bits (una respuesta si/no es 1 bit).
Pattern matching: detecta la presencia de un patrn de texto en un texto ms grande.
Indexacin: precomputar el pattern matching de manera fcil de ejecutar.
Text retrieval: recuperacin de la informacin
Idea:
No hacer comparaciones de claves completas, sino partes de ellas.
Requiere poder hacer operaciones sobre esas partes. Por ejemplo, si las claves son strings,
vamos a trabajar con caracteres. Si las claves son enteros, vamos a trabajar con dgitos o
bits.
Presuponemos que mirar una clave es ms costoso que mirar un cachito.
Desventajas:
Algunas implementaciones pueden requerir mucha memoria.
Las operaciones sobre las componentes de las claves puede no ser fcil, o ser muy
ineficiente en algunos lenguajes de alto nivel.
Es decir, no siempre es verdad que nuestra presuncin sea verdadera, depende de
algunos lenguajes
Un lenguaje de programacin de alto nivel se caracteriza por expresar los algoritmos de una manera adecuada a la
capacidad cognitiva humana, en lugar de la capacidad ejecutora de las mquinas.
En los primeros lenguajes, la limitacin era que se orientaban a un rea especfica y sus instrucciones requeran de
una sintaxis predefinida. Se clasifican como lenguajes procedimentales o lenguajes de bajo nivel. Otra limitacin de
estos es que se requiere de ciertos conocimientos de programacin para realizar las secuencias de instrucciones
lgicas. Los lenguajes de alto nivel se crearon para que el usuario comn pudiese solucionar un problema de
procesamiento de datos de una manera ms fcil y rpida.

Comentario: Buscar
explicaciones del resto de las cosas

Por esta razn, a finales de los aos 1950 surgi un nuevo tipo de lenguajes de programacin que evitaba estos
inconvenientes, a costa de ceder un poco en las ventajas. Estos lenguajes se llaman de tercera generacin o de
nivel alto, en contraposicin a los de bajo nivel o de nivel prximo a la mquina.
Un lenguaje de programacin de bajo nivel es aquel en el que sus instrucciones ejercen un control directo sobre el
hardware y estn condicionados por la estructura fsica de la computadora que lo soporta. El uso de la
palabra bajo en su denominacin no implica que el lenguaje sea inferior a un lenguaje de alto nivel, si no que se
refiere a la reducida abstraccin entre el lenguaje y el hardware. Por ejemplo, se utiliza este tipo de lenguajes para
programar tareas crticas de los Sistemas Operativos, de aplicaciones en tiempo real o controladores de dispositivos.

rboles de bsqueda digital:


Son parecidos a los ABB. Para guardar una clave vamos recorriendo el camino en el rbol
que nos lleva a su posicin. Pero la posicin no est determinada por comparaciones de
mayor o menor sino por los bits (o dgitos, o caracteres) de la clave.
Lo que cambia con el ABB es la pregunta que se hace para saber si vamos para la izquierda
o la derecha. Mira el elemento que est buscando bit por bit y si es un cero va a la izquierda,
y si es un 1 va a la derecha.
Cdigo de 5 bits, solo para las letras del abcdario
Bit es el acrnimo Binary digit (dgito binario). Un bit es un dgito del sistema de numeracin binario. Las unidades
de almacenamiento tienen por smbolo bit.1
Mientras que en el sistema de numeracin decimal se usan diez dgitos, en el binario se usan solo dos dgitos, el 0 y
el 1. Un bit o dgito binario puede representar uno de esos dos valores: 0 o 1.
Se puede imaginar un bit como una bombilla que puede estar en uno de los siguientes dos estados: apagada o
encendida
El bit es la unidad mnima de informacin empleada en informtica, en cualquier dispositivo digital, o en la teora de
la informacin. Con l, podemos representar dos valores cuales quiera, como verdadero o falso, abierto o cerrado,
blanco o negro, norte o sur, masculino o femenino, rojo o azul, etc. Basta con asignar uno de esos valores al estado
de "apagado" (0), y el otro al estado de "encendido" (1).

Propiedades:
*El peor caso es mucho mejor que el de los ABBs si:
- El nmero de las claves es grande
- Las claves no son largas
Esta estructura de datos depende del orden de insercin. La complejidad depende de la
profundidad del rbol y esta depende del orden de la insercin.
*Longitud del camino ms largo: es igual al mayor nmero de bits sucesivos iguales de dos
claves cualesquiera a partir del bit ms a la izquierda (o sea, el mayor prefijo comn)
El peor de los casos sera la longitud de la clave ms larga (o, para ser ms precisos: la
longitud de los prefijos ms largos compartidos por distintas claves nos da la
profundidad del rbol).
Ac tiene importancia el tamao de la clave, y en los ABB importa la cantidad de
elementos del diccionario.

Tenemos U: universo de las claves posibles y dentro de este esta D, el diccionario, con
n: cantidad de elementos distintos en mi diccionario.
n <= U por lo que log n <= log U, pero Cul es la relacin entre n y log U.
Si el rbol es corto, la cota basada en log U puede ser mejor que n.
El costo es proporcional multiplicado a lo que pago en cada nivel del rbol. En cada
nivel, para ver si coinciden, tengo que hacer una comparacin de clave completa.
Tambin tenemos una cota que vincula n con el tamao del diccionario.
*Bsqueda o insercin en un rbol de n claves de b bits, necesita en promedio (Suponiendo
1) log n comparaciones de clave completa, y b en el peor caso.
(1) Solamente tenemos permiso para hacer anlisis del caso promedio o esperado
cuando estamos realmente seguros de las hiptesis probabilsticas. Tenemos que
saber bajo qu condiciones. Suponer que el input est equidistribuido no es verdad.
Las leyes de la probabilidad si es equiprobable que un bit cualquiera pueda ser 0 o 1
entonces la profundidad de n claves es log (n) (si son muchas claves, no algo acotado)
La probabilidad de insertar otro carcter en esa cadena es de 1/2x siendo x el nivel del
rbol.
Tries
Debidos a Friedkin en los aos 60. El nombre proviene de retrieval (recuperacin). Es un
rbol (k+1)-ario para alfabetos de k elementos.
Los ejes del rbol toman inters: representan componentes de las claves. Por ejemplo: si las
claves son strings, los ejes representan caracteres, si las claves son enteros, los ejes
representan dgitos o bits.
Cada subrbol representa al conjunto de claves que comienza con las etiquetas de los ejes
que llevan hasta l
Los nodos internos no contienen claves.
Las claves o los punteros a la info se almacenan en las hojas (a veces ni eso es necesario).
No son rboles binarios. No siempre tiene que ser (k+1)-arios, en algunos casos no hace
falta el +1.
En las estructuras anteriores las claves se guardaban en los nodos. Ahora ya no se van a
guardar en los nodos, pero tampoco en los ejes (arco/flecha/raya/link).
La informacin va a estar asociada (y no guardada) a los ejes. Si la informacin son
strings, cada eje va a estar asociado con caracteres. Luego, una secuencia de ejes ser
una secuencia de caracteres (equivalente a un string).
Funcin de abstraccin: cada subrbol representa al conjunto de clavesNingn eje
lleva a la raz, el rbol completo, representa entonces todas las claves que comienzan
con nada, es decir, todas las claves posibles.

En los nodos no hay ms que links a los nodos de abajo. El link+1 es por ejemplo el $,
para marcar que algo es clave. El primer $ no es necesario?
En las hojas puedo querer guardar el link al significado.

Otro ejemplo:

En este caso todas tienen la misma altura, esto porque todas tienen 5 bits.
Adems, hay una sola manera de ponerlas.
Si todas tienen la misma cantidad entonces no hace falta el smbolo $ porque ninguna va a
ser prefijo de otra.
Propiedades:
*A lo sumo una comparacin de clave completa (cuando llego a una hoja).
*La estructura del trie es la misma, independientemente del orden en el que se insertan las
claves (o sea, hay un nico trie para un conjunto de claves).
* Bsqueda/insercin en un trie construido a partir de n claves de b bits, necesita ~log n
comparaciones de bits en promedio (suponiendo 1) y b comparaciones en el peor caso.

Para buscar, encontrar o insertar, mi costo es proporcional a la altura del rbol, y la


altura del rbol es la longitud de la clave ms larga.
Mi costo en cada nivel es O(1), a lo sumo cuando llegue a la hoja estara en clave
completa, pero nunca tengo que hacer operaciones en clave completa.
Ejemplo poblacin DNIs:
|U| = 108 (todos los dnis posibles)
n = 4 . 107 (cantidad de habitantes) CASO 1
n = 50 (alumnos en el aula) CASO 2
En el caso 2 log n << log |U|, en el caso 1 ambos tienen profundidad 8.
Implementacin de tries:
Una primera posibilidad es poniendo en cada nodo interno un arreglo de punteros.
Es muy eficiente en trminos de tiempo. Algoritmo simple. Puede ser extremadamente
ineficiente en trminos de memoria, especialmente cuando el alfabeto es grande o el
diccionario es chico (o las dos cosas juntas?).
Mitigaciones posibles: por ejemplo, agrupar caracteres poco frecuentes.
El link de $ no hace falta que sea a otro nodo pero tampoco puede ser a nil.
El costo verdadero en cada nivel es O(1) (voy a la posicin del array), pero gasta mucha
memoria. Si todas las posiciones estn ms o menos llenas, estoy aprovechando bien el
espacio, pero si no
Para cada nodo hay un tamao constante, pero no es lo mismo 2 que 26.
Una segunda posibilidad: hijos de un nodo representados a travs de una lista encadenada.
Es eficiente en trminos de tiempo, solo si hay pocas claves. Requiere algoritmos sobre
listas y es mucho ms eficiente en trminos de memoria.
Ventajas: usamos no ms del espacio que necesitamos (ms el espacio de los punteros).
Desventajas: no accedemos en O(1) si no que hay que buscar en una lista, O(n) (con n
elementos en la lista).
En este caso cada nodo son dos punteros, uno al mayor de los hijos y uno al hermano
siguiente.
Tries compactos
Son parecidos, pero colapsamos las cadenas que llevan a las hojas.
Guardamos la clave completa antes. Caminos completos que representan solo un nodo al
final, los subo y los compacto. Tambin se pueden compactar caminos sin bifurcaciones.

Tries ms compactos: Patricia


Patricia: Practical Algorithm to Retrieve Information Coded in Alphanumeric
Debidos a D.R. Morrison.
Ahora colapsamos todas las cadenas y un eje puede representar ms de un carcter.

La altura de un rbol Patricia binario est acotada por n (el nmero de claves). Eso no
sucede con los modelos anteriores. En realidad, Patricia es un poco ms elaborado y hay
numerosas variantes de los mtodos vistos hoy
En general usamos esta versin. Variantes pueden ser: Pat-Arrays, Suffix trees, Suffix
Arrays.
NOTA: se puede ver ms ac: http://es.wikipedia.org/wiki/Arreglo_de_sufijos
COLAS DE PRIORIDAD Y HEAPS
Colas de prioridad:

Tienen numerosas aplicaciones: Sistemas operativos, algoritmos de scheduling, gestin de


colas en cualquier ambiente, etc.
La prioridad en general la expresamos con un entero, pero puede ser cualquier otro tipo
con un orden < asociado.
Correspondencia entre mxima prioridad y un valor mximo o mnimo del valor del tipo .
TAD Cola de prioridad(,<

Observadores bsicos
vaca?: colaPrior(,<

) bool

prximo: colaPrior(, <

) c

desencolar: colaPrior(, <

(~vaca?( c ))

) c colaPrior(,< )

(~vaca?( c ))
Generadores
vaca: colaPrior(,<

encolar: colaPrior(,<

) colaPrior(,< )

Otras Operaciones
=colaPrior : colaPrior(,<

) colaPrior(,< ) bool

Cuadro comparativo de complejidad segn la implementacin


O
Array ord.
Listas ord.
Array desord.
Listas desod
ABB
AVL

Encolar
N
N
1
1
N
log (n)

Prximo
1
1
n
n
n
log (n) *2

Desencolar
1
1
n
n *1
n
log (n)

Heap

log (n)

log (n)

*1) Sera n+1 si consideramos la bsqueda en prximo


*2) Podra tener O(1) si guardo un puntero al mximo.
La implementacin ms eficiente es a travs de heaps. Heap significa literalmente montn.
Cola de prioridad (,<) se representa con heap.
Invariante de representacin (condicin de heap):
1. Es un rbol binario perfectamente balanceado
2. La clave (prioridad) de cada nodo es mayor o igual a la de sus hijos, s los tiene.
3. Todo subrbol es un heap
4. (no obligatorio) es izquierdista, o sea, el ltimo nivel est lleno desde la izquierda.
No es un ABB ni una estructura totalmente ordenada.
EJERCICIO: hacer la funcin de abstraccin

Es una estructura ms simple e igual de eficiente que los AVL. Heap: parva, montn,
montculo, pila.
Propiedades: est ms o menos ordenado. Tienen el orden justo para poder hacer lo que
queremos, pero no tanto como para que ordenar no tenga que ser demasiado complicado.
En un rbol perfectamente balanceado todas las ramas tienen la misma longitud excepto
+-1 (todas! Que es ms fuerte que el AVL).
A diferencia de los tries, hay informacin guardada en los nodos.
La altura es log(n).
Max- y Min-heap
Se llama Maxheap cuando la raz es el nodo de mayor valor, min-heap, el menor.
Operaciones sobre un (max)heap
Vaca: crea un heap vaco
Prximo: devuelve el elemento de mxima prioridad sin modificar el heap.
Encolar: agrega un elemento nuevo y hay que reestablecer el invariante
Desencolar: elimina el elemento de mxima prioridad, hay que restablecer el invariante.
implementacin
Todas las representaciones usadas para rboles binarios son admisibles:
- Representacin con punteros, eventualmente con punteros hijo-padre (para que las
complejidades sean reales necesitamos que cada nodo apunte tambin a su padre).
- Representacin con arrays, particularmente eficiente.
Representacin con arrays
Cada nodo v es almacenado en las posicin p(v).
- Si v es la raz, entonces p(v) = 0
- Si v es el hijo izquierdo de u, entonces p(v) = 2 p(u) + 1
- Si v es el hijo derecho de u, entonces p(v) = 2 p(u) + 2
Para la implementacin con arrays es necesario el izquierdismo. Esta representacin
es esttica, ocupa siempre la misma cantidad de memoria.
Ventajas: muy eficiente en trminos de espacio. Facilidad de navegacin: padre i => hijo
izq = 2i+1, hijo der = 2i+2; hijo i -> padre j => j = |(i-1)/2|
Desventaja: implementacin esttica (puede ser necesario duplicar el arreglo, o achicarlo, a
medida que se agregan/eliminan elementos).
Algoritmos
Prximo: El elemento de prioridad mxima est en la posicin 0 del arreglo. Operacin de
costo constante O(1).
Encolar(elemento):

* Insertar el elemento al final del heap


* Subir (elemento)
Subir(elemento):
* while (elemento no es raz) yl (prioridad(elemento) > prioridad(padre(elemento)))
- intercambiar elemento con padre.
Primero lo ubico debajo de todo, luego, si su clave es menor que la del padre lo dejo ah,
y si no intercambio posiciones. Costo O(log (n))
Desencolar
* Reemplazar el primer elemento con la ltima hoja y eliminar la ltima hoja.
* Bajar (raz)
Bajar(p)
* while (p no es hoja) yl (prioridad(p) < prioridad(algn hijo de p))
- intercambiar p con el hijo de mayor prioridad.
Saco la raz, al ltimo lugar lo ubico en la raz y luego lo intercambio con el mayor de
sus dos hijos, y luego con el mayor de sus dos hijos hasta que llega a ser hoja o tiene
dos hijos menores que l.
El segundo mayor es uno de los dos hijos de la raz. El tercer mayor podra ser el otro
de los dos hijos o algn hijo del segundo mayor. El cuarto podra estar entre el segundo
y el 4to nivel, y as sucesivamente.
Costo de desencolar O(log(n))
Qu pasa si se va un elemento que no es la raz? Cmo restablezco el invariante?
Array2heap:
Dado un arreglo cualquiera, lo transformo en un array que representa un heap a travs de
una permutacin de sus elementos.
Algoritmo simple:
Para i desde 1 hasta tam(array)
Encolar(array[i])
El costo (utilizando la aproximacin de Stirling del factorial):

Empiezo a encolar devuelta:

i=1 hasta n log(i) = log n! < i=1 hasta n log n = O(n log n)
En realidad es (n log n) (la sumatoria de los logaritmos es el logaritmo del producto).
heapordenar algo as, me cuesta lo mismo (o ms?) que ordenar del todo

En matemticas, la frmula de Stirling es una aproximacin para factoriales grandes. Lleva el nombre en honor al
matemtico escocs del siglo XVIII James Stirling.
La aproximacin se expresa como

para n suficientemente grande, donde ln es el logaritmo natural.

Algoritmo de Floyd:
Esta basado en la idea de aplicar la operacin Bajar() a rboles binarios tales que los hijos
de la raz son races de heaps.
Progresivamente de heapifican (heapify) los subrboles con raz en el penltimo nivel,
luego los del antepenltimo, etc. Estrategia bottom-up.
En vez de subir reiteradas veces, le aplico una raz y empiezo a bajar, lo que obtengo es
un heap.
Lo que hago es empezar desde debajo de todo del rbol y voy armando pequeos heaps
y los uno a una raz.

Anlisis del algoritmo de Floyd:


En el caso peor, cada llamada a bajar hace el mximo nmero de intercambios.
Suponemos un heap con n = 2k + 1 nodos (rbol binario completo de altura k)
- En el ltimo nivel hay (n+1)/2 hojas
- En el penltimo hay (n+1)/4 nodos
- En el antepenltimo (n+1)/8
- Y as sucesivamente nh = ni +1
Una llamada de bajar sobre un nodo de nivel i, provoca como mximo k-i intercambios
(operacin dominante): 1 intercambio si i es penltimo nivel, 2 si es el antepenltimo,, ki si i=1.
La cantidad mxima de intercambios es igual a:
Cant. De nodos en el penltimo nivel *1 + cant. Nodos en el antepenltimo nivel * 2 + +
cant de nodos en el nivel 2 * (k-2) + cant de nodos en el nivel 1 * (k-1)
Con k = lg(n+1)
La mitad de los nodos, y un poquito ms son hojas, y las hojas son gratis porque ya
son heaps.
de nodos es O(1) porque a lo sumo es un swap de un padre con solo dos hijos
1/8 paga como mximo 2

cantidad mxima de intercambios = ((n+1)/4) * 1 + ((n+1)/8) * 2 + + 2 (lg (n+1)-2) + 1


(lg(n+1)-1).
Cant mxima de intercambios =

Considerando que:

Deducimos que:

Por lo tanto el mximo de intercambios es O(n)


Aplicaciones del Algoritmo de Floyd:
Implementacin de operaciones no Standard:
Eliminacin de una clave cualquiera. Pueden ser requeridas en algn contexto. Ejemplo:
kill de un proceso dado su PID
(http://es.wikipedia.org/wiki/Proporcional_integral_derivativo)
O(n) para encontrar la clave, O(1) para eliminarla, O(n) para reconstruir el invariante de
representacin con el Algoritmo de Floyd.
En el heap no se puede hacer bsqueda binaria, el costo de buscar un elemento es O(n)
ORDENAMIENTO (Sorting)
Uno de los problemas ms clsicos, tiles y estudiados de la informtica es el de
Ordenar: arreglo[] arreglo[], donde es un tipo tal que est definida la relacin < .
Variante: ordenamiento en memoria secundaria (por ejemplo grandes archivos).
Si a es distinto de b ambos de tipo => a < b o b < a a < b? a O(1)
Selection sort
Algoritmo:
Repetir para las posiciones sucesivas i del arreglo:
- Seleccionar el mnimo elemento que se encuentra entre la posicin actual y la final.
- Ubicarlo en la posicin i, intercambindolo con el ocupante original de esa
posicin.

Invariante:
- Los elementos entre la posicin 0 y la posicin i son los i + 1 elementos ms
pequeos del arreglo original.
- Los elementos entre la posicin 0 y la posicin i se encuentran ordenados.
- El arreglo es una permutacin del arreglo original (o sea, los elementos entre las
posiciones i+1 y n-1 son los n-i-1 elementos ms grandes del arreglo original.
Para i desde 0 hasta n-2 hacer:
- min <- seleccionar_min(i, n-1)
- Intercambiar(i, min)
Para i desde 0 hasta n-2 hacer:
- min <- i
- Para j desde i+1 hasta n-1 hacer
- Si a[j] < a[min] entonces min <- j
- Intercambiar(i, min)
Versin recursiva:
Para ordenar un arreglo de posiciones i n-1
- Seleccionar el mnimo elemento del arreglo
- Ubicarlo en la posicin i, intercambindolo con el ocupante original de esa
posicin.
- Ordenar a travs del mismo algoritmo las posiciones i+1n-1
Es la repetida seleccin del mnimo que no est ordenado.
Tiempo de ejecucin:
Para medir el tiempo, medimos la cantidad de operaciones. Alcanza con contar la cantidad
de comparaciones.
Arreglo con n elementos. N-1 ejecuciones del ciclo principal. En la i-sima iteracin hay
que encontrar el mnimo entre n-i elementos y por lo tanto necesitamos n-i-1
comparaciones:

Observar que el costo no depende del eventual ordenamiento parcial o total del arreglo. En
caso peor, mejor y promedio es O(n2)
Es SIEMPRE O(n2) y NO es estable
Insertion Sort
Invariante:
- Los elementos entre la posicin 0 y la posicin i son los elementos que ocupaban las
posiciones 0 a i del arreglo original.
- Los elementos entre la posicin 0 e i se encuentran ordenados.
- El arreglo es una permutacin del arreglo original (o sea que los elementos de las
posiciones i+1 hasta n-1 son los que ocupaban esas posiciones en el arreglo original).

Algoritmo:
Repetir para las posiciones sucesivas i del arreglo:
- Insertar el i-simo elemento en la posicin que le corresponde del arreglo 0i
Voy insertando ordenado en un nuevo array.
Para i desde 1 hasta n-1 hacer
- Insertar(i)
Para i desde 1 hasta n-1 hacer
- j <- i-1, elem <- a[i]
- mientras j>=0 y luego a[j] > elem hacer
- a[j+1] <- a[j]
- j <- j-1
- a[j+1] <- elem
Podra hacer bsqueda binaria sobre la primera parte (que ya est ordenada), pero de
todas formas, en el peor caso tengo que correr n elementos.
Tiempo de ejecucin:
Arreglo con n elementos, n-1 ejecuciones del ciclo principal. En la i-sima iteracin hay
que ubicar al elemento junto a otros i-1 elementos y por lo tanto necesitamos i-1
comparaciones.

Observar que si el arreglo est parcialmente ordenado, las cosas mejoran (y si est
ordenado al revs?)
Estabilidad: un algoritmo es estable si mantiene el orden anterior de elementos con igual
clave.
Para qu sirve la estabilidad?
Son estables los algoritmos que vimos hasta ahora?
El insertion sort es estable. Primero ordeno por el segundo criterio, despus hago una
segunda pasada con el otro criterio. Con el algoritmo estable se va a mantener el orden
por el segundo criterio tambin.
El insertion sort tiene muchos casos buenos y es estable. En el peor caso es O(n2)
Heapsort
Valor de la estructura de datos: Seleccin Sort usa n bsquedas de mnimo. Para hacerlo
eficientemente puedo meter los elementos del arreglo uno a uno en un heap y luego ir
sacndolos.

Comentario: Esto es importante


y tendra que ver bien que pasa si
est ordenado al revs!!

Inserto los n elementos en un heap, obtengo el mnimo en O(1) pero igual lo tengo que
sacar y eso ya no es O(1) si no O() Esto todava no es un Heapsort
Recordemos Array2heap y el algoritmo de Floyd: complejidad O(n)
Algoritmo de ordenamiento de un array basado en un heap:
- heap <- array2heap(A)
- para i desde n-1 hasta 0 hacer
- max <- prximo(heap)
- desencolar
-A[i] <- max
Costo: O(n) + O(n log n) = O(n log n)
Notar que no requiere memoria adicional.
Inserto los h elementos de A en H (heap) y luego voy sacando el mnimo de H en O(1)
y lo paso nuevamente (y ordenado) a A. Luego agarro el ltimo elemento de H, lo
pongo al principio y aplico bajar (el tamao de H disminuye en 1), un heap de n
elementos ocupa las posiciones de 0 a n-1.
Entonces heapificamos el mismo array pero hacemos un max-heap. Vamos tomando el
mximo, lo sacamos y lo insertamos atrs de todo, cada vez ms a la derecha.
Esto es heap sort y NO es estable.
Merge Sort
Clsico ejemplo de Divide and conquer.
La metodologa consiste en:
- dividir un problema en problemas similares pero ms chicos.
- Resolver los problemas menores
- Combinar las soluciones de los problemas menores para obtener la solucin del
problema original.
El mtodo tiene sentido siempre y cuando la divisin y la combinacin no sean
excesivamente caras.
Este algoritmo es atribuido por Knuth a Von Neumann (1945)
Algoritmo:
- si n<2 entonces el arreglo ya est ordenado.
- en caso contrario
- Dividir el arreglo en dos partes iguales (o sea, por la mitad)
- Ordenar recursivamente (o sea, a travs del mismo algoritmo) ambas mitades.
- Fundir ambas mitades (ya ordenadas) en un nico arreglo.
Costo (suponiendo n = 2k)

Y si n no fuera igual a k?
Si n no es potencia de 2 puedo decir que 2k-1 <n <= 2k => T(n) <= T(2k)
Si n = k entonces k = log2 n.
Para demostrar falta la induccin en k. Si n no es 2k entonces tomo 2k.
El merge/fusin toma O(n).
Solo podemos dividir siempre en dos partes iguales si n es potencia de 2. De todas
formas funciona siempre que divida en dos partes lo ms parejas posibles.
Tenemos O(log(n)) pasos ya que hay log n columnas y en cada columna a lo sumo hay
n comparaciones y menos de n divisiones, por lo que el costo es O(n log n)
Quick sort
Idea en cierto modo parecida, divide and conquer. Debido a C.A.R. Hoare. Muy estudiado,
analizado y utilizado en la prctica.
Supongamos que conocemos el elemento mediano del arreglo.
Algoritmo
- Separar el arreglo en dos mitades: los elementos menores que el mediano por un lado y
los mayores por el otro.
- Ordenar las dos mitades.
Encuentro el mediano divido a partir de el, ordeno cada parte recursivamente y luego
unirlas es gratis.
Y si no conocemos el mediano?
Si no conocemos el mediano agarramos uno cualquiera como bound/pivote.

1/n! = 1/n * 1/n-1 * 1/n-2


Hay muy pocos casos malos y muchos cercanos al promedio
Quicksort(array[]) {
If (array.length <1) {
Elegir bound; /* subarray 1 y subarray 2*/
While (haya elementos en el array)
If (elemento genrico < bound)
Insertar elemento en subarray 1
Else insertar elemento en subarray 2;
Quicksort(subarray 1);
Quicksort(subarray 2);
Vamos a tener 2 punteros, lower y upper, el primero avanza desde el principio al final del
arreglo y el segundo del final al principio.
Se busca el mximo y se lo ubica al final, esto sirve para que lower no se pueda ir de rango.
Se elige como pivote el del medio y provisoriamente se lo ubica al inicio.
Cuando se cruzan lower y upper se acaba la iteracin.
Con lower vamos buscando elementos ms grandes que el pivote, si encontramos
alguno paramos.
Con upper buscamos elementos ms chicos que el pivote, si encontramos alguno
paramos.
Si lower y upper estn cruzados terminamos y pasamos al siguiente paso.
Si no, los intercambiamos y repetimos el procedimiento.
Guardamos el pivote en el primer lugar del array porque as cuando venimos de derecha
a izquierda a lo sumo llegamos hasta el pivote y nos pasamos de 0 y lo mismo con el
mximo (que solo lo buscamos en el primer paso). Esto sirve para no tener que estar
preguntando en cada paso si me estoy pasando (de 0 y n)

Comentario: Honestamente no
tengo idea a qu vena esta cuenta?

Anlisis:
Costo = O(nro. de comparaciones)
Costo = O(n2) en el peor caso
Costo = O (n log n) en el caso mejor y promedio.
En la prctica el algoritmo es eficiente. La eleccin del pvot es fundamental.
El anlisis del caso promedio dice que la probabilidad de encontrar el peor al elegir el
pivote es de 1/n (por es 1/n! por la cantidad de veces que tengo que elegir el pivote)
Otra posibilidad, si alguien a propsito siempre me pone el peor en el medio, es elegir
el pivote al azar y la probabilidad de elegir siempre el peor entonces depende de 1/n!
Los algoritmos son objetos determinsticos que se comportan exactamente igual ante las
mismas condiciones. Quicksort es un algoritmo probabilstica, utiliza el azar y su
resultado es una variable aleatoria o siempre el mismo y su complejidad aleatoria?
El costo esperado de QS eligiendo el pivote al azar se va a acercar a O(n log n)
Caso peor: El elemento del pvot es siempre el mnimo (me queda un nico subarray con el
resto de los elementos). Tengo n-1, n-2, n-3 2, 1 comparaciones en cada iteracin (n-1
veces). El costo es = (n-1 + n-2 + n-3 + + 2 + 1) = O(n2)

Caso mejor: Divido siempre justo a la mitad. (suponemos n potencia de 2 por


simplicidad).
Las comparaciones en cada iteracin sern: n-1, n/2 1, n/4 1,,2,1 (log n+1 veces)

Caso promedio:
En un input al azar, proveniente de una distribucin uniforme, la probabilidad de que el
elemento i-simo sea el pvot es 1/n
Tendramos entonces la recurrencia:

Ojo! No siempre podemos suponer que el input proviene de una distribucin uniforme, pero
podemos forzarlo, permutando el input, o bien eligiendo el pivote al azar (Algoritmos
probabilisticos)
Si elijo al azar, la probabilidad de que caiga en una posicin es 1/n para todas las
posiciones

i=1 hasta n 1/n * i ~ n/2 ?


Elijo de alguna manera y va a parar a la posicin i. tengo un costo para repartir y uno
para ordenar cada parte. Suponiendo que el tamao del arreglo es n:
T(n) = T(i-1) + T(n-i)
E(T(n) = 1/n T(i-1) + T (n-i)
E es la esperanza de costo, y supongo el 1/n es la probabilidad de elegir el pvot?
O(n log n)
Complejidad de los algoritmos de ordenamiento:
MergeSort y HeapSort: O(n log n)
Quick Sort, Selection Sort e Insertion Sort O(n2)
- Quick Sort O(n log n) en el caso mejor
- Selection Sort O(n2) en todos los casos
- Insertion Sort O(n) en el caso mejor.
Lower Bound (lmites inferiores)
Cul es la eficiencia mxima (complejidad mnima) obtenible en el caso peor.

Comentario: Lo acabo de
inventar

Vamos a cuantificar sobre todos los posibles algoritmos de ordenamiento basados en


comparacin (hay otro tipo basado en la representacin de los nmeros??)
Todos los algoritmos deben comparar elementos (ese es nuestro modelo de cmputo).
Dados ak y ai hay tres casos posibles ak < ai, ak > ai, ak = ai
Se asume por simplicidad que todos los elementos son distintos, entonces todas las
comparaciones tienen la forma ak < ai y el resultado de la comparacin es verdadero o falso.
(Si los elementos pueden tener valores iguales entonces se consideran solamente
comparaciones del tipo ak <= ai )
rboles de decisin

Un rbol de decisin representa las comparaciones ejecutadas por un algoritmo sobre un


input dado.
Cada hoja corresponde a una de las posibles permutaciones.
Hay n! posibles permutaciones por lo que el rbol debe contener n! hojas.
La ejecucin de un algoritmo corresponde a un camino en el rbol de decisin
correspondiente al input considerado.
El camino ms largo de la raz a una hoja (altura) representa el nmero de comparaciones
que el algoritmo tiene que realizar en el caso peor.
Teorema: cualquier rbol de decisin que ordena n elementos tiene altura (n log n)
Demostracin:
- rbol de decisin es binario
- con n! hojas
- Altura mnima (log(n!)) = (n log n) (log n! a n log n)
Corolario: Ningn algoritmo de ordenamiento tiene complejidad mejor que (n log n)
Corolario: Los algoritmos Merge Sort y Heap Sort tienen complejidad asinttica ptima.
Nota: Existen algoritmos de ordenamiento con complejidad ms baja pero requieren ciertas
hiptesis sobre el input.
http://www.cs.ubc.ca/~harrison/Java/sorting-demo.html

Lista de algoritmos de ordenamiento[editar]


Algunos algoritmos de ordenamiento agrupados segn estabilidad tomando en cuenta
la complejidad computacional.
Estables
Nombre traducido

Nombre original

Complejidad

Memoria Mtodo

Ordenamiento de burbuja

Bubblesort

O(n)

O(1)

Intercambio

Ordenamiento de burbuja bidireccional

Cocktail sort

O(n)

O(1)

Intercambio

Ordenamiento por seleccin

Selection Sort

O(n)

O(1)

Intercambio

Ordenamiento por insercin

Insertion sort

O(n)

O(1)

Insercin

Ordenamiento por casilleros

Bucket sort

O(n)

O(n)

No comparativo

Ordenamiento por cuentas

Counting sort

O(n+k)

O(n+k)

No comparativo

Ordenamiento por mezcla

Merge sort

O(n log n)

O(n)

Mezcla

Ordenamiento con rbol binario

Binary tree sort

O(n log n)

O(n)

Insercin

Pigeonhole sort

O(n+k)

O(k)

Radix sort

O(nk)

O(n)

Distribution sort

O(n) versin recursiva

O(n)

Gnome sort

O(n)

O(1)

Ordenamiento Radix

No comparativo

Inestables
Nombre traducido
Ordenamiento Shell

Nombre original

Complejidad

Memoria Mtodo

Shell sort

O(n

1.25

O(1)

Insercin

Comb sort

O(n log n)

O(1)

Intercambio

Ordenamiento por seleccin

Selection sort

O(n)

O(1)

Seleccin

Ordenamiento por montculos

Heapsort

O(n log n)

O(1)

Seleccin

Smoothsort

O(n log n)

O(1)

Seleccin

Quicksort

Promedio: O(n log n),


peor caso: O(n)

O(log n)

Particin

Ordenamiento rpido

Promedio: O(n u),


Several Unique Sort

peor caso: O(n);


u=n; u = nmero nico de registros

INSERTION SORT: Se va insertando en el lugar correspondiente cada elemento en un


arreglo ordenado. Son n elementos e insertar ordenado cuesta O(n)
SELECTION SORT: Busca el mnimo elemento entre la posicin i y el final de la lista,
lo intercambia con el elemento en la posicin i e incrementa i. Buscar el menor cuesta
O(n) y son n elementos.
BUBBLE SORT: Semejante a Selection Sort, solo que mientras busca el menor va
moviendo su candidato a menor para adelante.
MERGE SORT: Algoritmo recursivo que ordena dos mitades y luego las fusiona
QUICK SORT: Elige un pvot, separa los elementos entre los menores y los mayores a l.
Luego se ejecuta el mismo procedimiento sobre cada una de las partes.

HEAP SORT: Arma el heap en O(n) y va sacando los elementos ordenados pagando
O(log n) cada vez.
BUCKET SORT: Asume que los elementos pertenecen a un intervalo [0,M) y son
generados aleatoriamente, en forma independiente y tienen distribucin uniforme en
[0,M)
Particiona [0,M)en n intervalos iguales y les asocia n buckets.
Pone cada elemento del arreglo en el bucket correspondiente a su intervalo.
Ordena cada bucket y concatena los buckets ordenados
Es estable porque preserva el orden original entre las cosas equivalentes.
Particiona el intervalo. Como estn distribuidos uniformemente entonces en general
(promedio) voy a tener pocos elementos por bucket, O(n), aunque en el peor caso podran
quedar todos en el mismo bucket, entonces O(n2).
RADIX SORT: Est pensado para ordenar cadenas en orden lexicogrfico. Los
elementos de la cadena (que llamaremos dgitos) pueden ser cualquier cosa para la que
tengamos una relacin de orden.
La idea es hacer varias pasadas sucesivas (por todo el arreglo) de algoritmos de
ordenamiento estables, una por cada dgito, en orden creciente de importancia del dgito.
Aplicaciones sucesivas de algoritmos estables en orden creciente de importancia del
dgito permite lograr un orden lexicogrfico.
Sirve cuando la cantidad de elementos a ordenar es muy grande en comparacin a la
cantidad de dgitos.
La complejidad depende del algoritmo que usemos para cada dgito. Si asumimos que la
cantidad de valores que puede tomar el dgito es acotada, entonces se puede asumir que
cada pasada es O(n) y como tenemos k pasadas es O(kn)y si la longitud de la cadena es
acotada, es O(n)
COUNTING SORT: continuar
DIVIDE AND CONQUER
D&C es una tcnica algortmica que se basa en dividir un problema en varios subproblemas
ms chicos, resolverlos y combinar las soluciones.
Las subpartes tienen que ser ms pequeas que el problema original y todo debe ser el
mismo tipo de tarea (se llama recursivamente).
Consiste en tres etapas: Dividir, conquistar y combinar. Dividir y combinar pueden no ser
nulas, pero no tienen que ser demasiado costosas.
Por lo general todo el laburo se hace en la tercer parte.
Forma general:
F(X)
- Si X es suficientemente chico o simple, solucionar de manera ad hoc
- Si no:
- Dividir a X en X1, X2 Xk
- i < k, hacer Yi = F(Xi)

Comentario: Qu es y qu no
es una tcnica algortmica?
Pregunta en las diapos a la que no
tengo respuesta

- combinar los Xi en un Y que es la solucin para X.


- devolver Y
Cmo calculamos la complejidad de un algoritmo D&C?
El costo de un algoritmo D&C de tamao n se puede expresar como T(n), que debe
considerar:
- Dividir el problema en a subproblemas de tamao mximo n/c, siempre que n/c > n0 para
algn n0
- El costo de efectivamente hacer la subdivisin y luego unir los resultados.
- Si este costo es b cuando n = 1, entonces podemos expresarlo como b nd para algn d.
- Adems hay que resolver los subproblemas a T(n/c).
Es decir T(n) = a T (n/c) + b nd
T(n/c) es la llamada recursiva. En la bsqueda binaria por ejemplo hago 1 llamada
recursiva, pero me llamo con n/2.
El costo de dividir y combinar es polinomial (b nd para algn d)
Tengo entonces a llamadas recursivas de tamao n/c. c es constante una vez que defin
el problema.
Por ejemplo Merge Sort a = 2 c = 2. Bsqueda binaria a = 1 c = 2.
Cunto me cuesta dividir el trabajo y luego combinarlo?
Ejemplo
f(A) (A: array)
Selection Sort(A/2)
F(A/2)
F(A/2)
En cada paso tengo (n/2)2 + 2 T(n/2)
Supongamos que n = ck para algn k y analicemos la recurrencia (c es la cantidad de partes
en la que lo divido)

Comentario: Ya que estamos


estara bueno saber bien qu es un
polinomio

Seguimos teniendo una recurrencia. El caso base sera T(1):

Dividir y combinar me
cuesta independiente de la
cantidad de elementos
Dividir y combinar tienen
un costo lineal (ej: quick
sort)

Ej a = c Merge Sort

Teorema maestro:

El teorema maestro solo sirve cuando a y c son constantes. Si divido 2n veces, no puedo
usar este teorema
Multiplicacin entera:
Cul es la complejidad de multiplicar dos nmeros enteros?
El tamao de entrada de multiplicar dos enteros es el tamao de bits que tienen esos
nmeros. Si tengo un milln por ejemplo, agarro los primeros 4 dgitos, los multiplico por
104 y le sumo los ltimos dgitos.
Si tienen n dgitos en base b, la complejidad es O(n2)
Se puede hacer algo mejor, por ejemplo, expresndolos como una suma donde cada
sumando tiene aprox. La mitad de los dgitos.

Algoritmo de Karatsuba

Los pasos 2 y 3 son O(1) u O(n)? o cte?


Llevar la base a una potencia es desplazarla, entonces es lineal.
A=3, c=2
Log2 3= 1,59
Estamos en el primer caso del teorema maestro.
Este algoritmo por ah no tiene sentido para nmeros chicos, pero s para nmeros muy
grandes.
Otro ejemplo:
Tenemos un conjunto de puntos en un plano bidimensional y hay que encontrar los dos
vecinos ms cercanos entre s.
Ordenamos los puntos por su coordenada x, dividimos en dos y calculamos cada lado.
No sirve, porque podra tener dos muy cerca pero que quedaron uno de cada lado y no
los encuentra.
Podra decir cuando termines compar adems los que estaban ms cercanos a la lnea
de un lado con los que estaban ms cercanos a la lnea del otro. Pero en el peor caso
estn todos cerca de la lnea y otra vez tenemos n2.

La solucin dice que a lo sumo tenemos que comparar algunos puntos. Entonces:

T(n) = 2 T(n/2) + algunos n + c (donde c es el costo de decidir despus cual de los


algunos ltimos es el menor. Es cte.)
Estamos en el segundo caso entonces T(n) es O(n log n)
Cuando me llamo recursivamente voy a tener a los dos vecinos ms cercanos de la
derecha y los dos de la izquierda. Entonces tengo una distancia mnima de cada lado.
En lnea recta, tengo como mximo un punto ms lejano con el que comparar. Si
hubiera un punto en el medio (antes de la lnea) entonces la distancia ms corta hubiera
sido con ese punto.
En realidad no sabemos la justificacin fina.
ELIMINACIN DE LA RECURSIN Y TRANSFORMACIN DE PROGRAMAS
Revisemos la recursin. Empecemos por la sucesin de Fibonacci:
Fib(0) = 0
Fib(1) = 1
Fib(n+2) = Fib (n+1) + Fib(n)
Miremos; Fib(5) = Fib(4) + Fib (3) = (Fib(3) + Fib(2) ) + Fib(3)
Estamos calculando dos veces Fib(3). En realidad ya vemos en la definicin que
calculamos dos veces Fib(n)
Podramos hacer algo mejor. Idea:
Cada vez que calculo Fib(m) tengo que calcular Fib(m-1) y Fib(m-2).
Adems Fib(m+1) va a necesitar Fib((m+1)-1) y Fib((m+1)-2), es decir Fib(m-1) que ya lo
calcul recin. Y si hago que Fib(m) me devuelva tambin al Fib(m-1) que utiliz?
Fibonacci arreglada sera as:

La versin original toma O(2n) mientras que la nueva es lineal en n

Esto se llama Inmersin de rango y consiste en agregar un nuevo parmetro de salida a la


funcin. La idea de este nuevo parmetro es darnos algo ms que lo estrictamente
necesario, que nos sirve para calcular ms eficientemente otro resultado.
A esta tcnica tambin se la conoce como generalizacin de las funciones. En el ejemplo
Fib() es ms general que Fib().
La idea de la inmersin de rango puede servir tambin para hacer varias cosas a la vez.
Ejercicio: escribir una funcin que compute la cantidad de nodos y la altura mxima de un
rbol binario de naturales
Inmersin de dominio
La idea es similar. Se agrega un parmetro de entrada, que va conteniendo resultados
intermedios.
Pensemos en Promedio() de una secuencia, que requerira la suma y la cantidad.
Podemos hacerlo mejor:
Promedio (<>, suma, cantidad) = suma/cantidad
Promedio (a*S, suma, cantidad) = Promedio (S, suma+a, cantidad+1)
Suma y cantidad son parmetros de acumulacin. Agrand la entrada en lugar de la
salida
Otro clsico: x0 = 1 x n+1 = xn . x
Complejidad: n multiplicaciones y llamadas recursivas

Esta funcin hace aprox. La mitad de multiplicaciones. En el paso 2 lo que hicimos fue
desplegar la definicin de xn. En el 5 hicimos un plegado
A esta tcnica se la conoce como folding/unfolding o plegado/desplegado
El desplegado consiste en reemplazar la definicin de la funcin por su expresin.
El plegado puede pensarse como la inversa de lo anterior. Se trata de reemplazar la
definicin por una llamada a la funcin.
La estrategia ms comn consiste en desplegado, rearreglo, plegado. Ejemplo:

De alguna manera el refactoring es una forma de plegado


Refactoring: el cdigo te queda ms lindo ? Cambia parte del cdigo por llamadas a
funciones
Folding/unfolding en bases de datos:
Imaginemos una empresa multinacional. Queremos obtener la direccin de un cliente en
particular. Supongamos 10 millones de registros de los cuales 8 millones son argentinos.
En el lenguaje ms comn para consultas de bases de datos, SQL, esto se hara con
SELECT direccion FORM clientes_argentinos WHERE nombre =Carlos Lopez Pombo
Adems, clientes_argentinos, tradicionalmente estara definido como
SELECT * FROM clientes WHERE pais=Argentina
Hacer las consultas en el orden propuesto implica recorrer 10 millones de registros,
seleccionar de alguna manera a los 8 millones de argentinos, y luego volverlos a recorrer
para quedarme con 1
Desplegamos clientes_argentinos:
SELECT direccion FORM (SELECT * FROM clientes WHERE pais=Argentina)
WHERE nombre =Carlos Lopez Pombo
Reacomodamos usando reglas propias de este lenguaje
SELECT direccion FORM (SELECT * FROM clientes WHERE pais=ArgentinaAND
nombre =Carlos Lopez Pombo)
Seguimos reacomodando:
SELECT direccion FORM clientes WHERE pais=ArgentinaAND nombre =Carlos
Lopez Pombo
De esta manera resolvemos el problema en una sola pasada. Los motores de bases de datos
hacen estas cosas de manera automtica.
El problema de la recursin
Las computadoras reales son un problema. En las ficticias, los algoritmos se ven geniales.
En las reales, cada llamada a funcin requiere pasar los parmetros a la pila que es costoso
y consumen espacio de pila que es acotado.
En cambio, los compiladores suelen estar buenos, porque hubo gente que se dio cuenta de
que algunos de estos problemas se podan solucionar automticamente.
Cuando yo me llamo recursivamente, los registros son los mismos, entonces la
computadora va agarrando los valores y los pone en la pila, para que al volver a llamar est
en cero. Siempre es ms rpida una funcin iterativa que una recursiva.

Comentario: Ver bien qu era


esto, alguna funcin de algn
lenguaje, supongo

Algunos tipos de funciones recursivas se pueden hacer iterativas mecnicamente.


Ejemplo:
//Precondicin: x est en S
funcin BuscarPosicion(int x, secu S, int pos)
if(x==prim(S))
return pos
else
return BuscarPosicin(x, fin(S), pos+1)
La ltima operacin que se hace en este caso es la llamada recursiva.
Funciones recurisvas lineales a la cola/ recursivas a la cola/ recursivas lineales finales
El esqueleto sera as:
Funcin F(parmetros)
If (caso base(parmetros))
Return algn valor
Else
Return F(achicar(parmetros)
Se puede transformar en
Funcin F(parmetros)
While !(caso base(parmetros))
Parmetros = achicar(parmetros)
Return algn valor.
Su caracterstica es que su ltimo paso es la llamada recurisva y que esta es la nica
llamada recursiva. Pueden transformarse automticamente a iterativas. Los compiladores
suelen hacerlo.
Funciones recursivas lineales no a la cola
Ejemplo
Funcion Sumatoria(secu S)
If vacia?(s) return 0
Else return prim(S)+sumatoria(fin(S))
Lo ltimo que hago antes de retornar no es la llamada recursiva si no la suma.
Son aquellas que tienen una nica llamada recursiva (por eso lineales) pero donde esta no
es la ltima operacin.
Podemos usar la inmersin:
Funcion SumatoriaGeneralizada(int acumulador, secu S)
If vaca?(s) return acumulador
Else return SumatoriaGeneralizada(prim(s) + acumulador, fin(s))

As la transformamos en lineal a la cola y despus en iterativa.


Tambin pueden transformarse automticamente.
Funciones recursivas no lineales
Son aquellas que tienen ms de una llamada recursiva:
- Mltiple: Funciones como Fib(), que tienen ms de una llamada recursiva, pero no es la
ltima operacin.
- Anidada: Tienen mas de una llamada recursiva, anidada. Adems, la llamada recursiva
es la ltima operacin.
No siempre tenemos una forma de eliminar la recursin de las funciones anidadas y
podemos llevar las mltiples a anidadas, pero en muchos casos.
Recursiones mltiples:
Ejemplo
Pre(nil) = <>
Pre(bin(i,x,d)) = x(Pre(i)&Pre(d))
Para llevarla a anidada agregamos un parmetro de acumulacin (en particular, una
secuencia que representa el resultado parcial.
Buscamos que Pre(ab) = PreA(<>,ab) es decir que al principio el acumulador est vaco, y
PreA(<>, ab) = PreA(S,nil) para alguna secuencia S, es decir que tenga el resultado en el
acumulador al terminar de recorrer el rbol..
Veamos como quedara:

Pongamos un rbol en 1 y apliquemos plegado y desplegado:

PreA(acum, bin(i,x,d)) = PreA(acum & (x PreA(<>,i)), d)


Lo que nos qued es una recursin anidada.
NOTA: lo que hicimos fue proponer la transformacin y luego demostrar que es correcta.
Funciones recursivas anidadas
En estos casos la mejor estrategia suele ser el uso de una pila.
Vamos a querer que PreG(p, acum) = PreA(<>, ab) para alguna pila p
Para qu sirve la pila?

Comentario: No siempre
ambas cosas o siempre una pero no
la otra?

Propongo:
PreG(apilar(ab,p), acum.) = PreG(p, PreA(acum., ab))
Tiene sentido porque se p es la pila vaca y acum es la secuencia vaca, nos queda
PreG(apilar(ab,vacia), <>) = PreG(vacia, PreA(<>, ab)) que ya sabemos que es igual a
Pre(ab).
Ahora en lugar de inventar una transformacin y luego probar que es correcta, vamos a
deducirla.
Pongamos un rbol en la pila y veamos qu sucede:

En cada paso la pila crece, pero la cantidad total de elementos es ms chica, entonces es
una funcin que eventualmente termina.
Nos queda:

Como esta funcin es recursiva a la cola, podemos aplicar lo que ya sabemos


PreG es lineal a la cola, una nica llamada recursiva y es lo ltimo que hace. La
complejidad no cambi, es O(n), recorre todos los nodos del rbol haciendo otras cosas
en el medio.
Igual, la funcin iterativa tiene una pila, y la pila tiene una complejidad. Esto va a tener
mejor rendimiento para rboles suficientemente grandes.
Otras tcnicas de transformacin de programas.
- Generalizacin de gnero: Ejemplo: tal vez me conviene trabajar con enteros en lugar de
naturales, si tengo que restar.
- Si voy a usar el resultado de una funcin ms de una vez, probablemente convenga tenerlo
en una variable.

-De manera ms general, si ya comput resultados caros, puede tener sentido almacenarlos
(en memoria o en disco) en lugar de recomputarlos.
- Precomputar valores. Por ejemplo, si mi programa va a intentar factorizar, tal vez me
convenga tener almacenados los n primeros nmeros primos.
- Inversin del orden de cmputo
- Evaluacin parcial. Especializar en valores particulares. Ejemplo:

- Conceptos relacionados: curryficacin especializacin


Currificacin
En la ciencia de la computacin, currificar es la tcnica inventada por Moses
Schnfinkel y Gottlob Frege que consiste en transformar una funcin que utiliza
mltiples argumentos (o ms especficamente una n-tupla como argumento) en
una funcin que utiliza un nico argumento.

Definicin
Dada una funcin f del tipo

, currificndola sera una funcin del

tipo
. En otras palabras,
toma un argumento del
tipo
y retorna una funcin del tipo
. Descurrificar es la transformacin inversa.
Intuitivamente, la currificacin expone que "Si ajustas algunos argumentos, tendrs una
funcin de los argumentos restantes". Por ejemplo, si la funcin div significa la versin
currificada de la operacin x / y, entonces div con el parmetro x ajustado en 1 es otra funcin:
igual que la funcin inv que devuelve la inversa multiplicativa de sus argumentos, definida
por inv(y) = 1 / y.
La motivacin prctica para currificar es que en ocasiones, muy seguidas, las funciones
obtenidas al utilizar algunos, pero no todos, los argumentos en una funcin currificada pueden
resultar tiles; por ejemplo, muchos lenguajes tienen una funcin o un operador similar
a plus_one. Currificar hace fcil definir dichas funciones.

La evaluacin parcial o especializacin de programas puede entenderse como una tcnica


de transformacin que consigue la optimizacin del programa original para una clase de
datos de entrada. Dado un programa P y parte de sus datos de entrada in1, el objetivo de la
evaluacin parcial es construir un programa Pini1 que cuando se le introduce el resto de los
datos de entrada, in2 computa el mismo resultado que P con toda su entrada (in1+ in2).
Esto ltimo asegura la correccin de la transformacin
efectuada( http://www.academia.edu/506292/Especializacion_de_programas_logicofuncionales_perezosos)
Tarea: Hacer un programa que genere rboles binarios al azar. Programar PRe(), PreA(),
PreG() y una versin iterativa. Tomar tiempos (comando time en Unix).

(Con 0 al 3, 0 sin hijos, 1 con un hijo izquierdo, 2 con un hijo derecho, 3 con dos hijos)
SORTING Y SEARCHING EN MEMORIA SECUNDARIA
Motivacin:
Los problemas abstractos siguen siendo los mismos, pero el volumen de los datos hace que
los mismos se encuentren necesariamente en memoria secundaria.
En general, entran a jugar ciertos elementos de sistema adems de los algortmicos.
Tiempo de acceso a los elementos es mucho mayor que en memoria principal (tpicamente
1 milln de veces ms lento)
Costo principal: entrada-salida. Por ej: invertir un gran archivo ya es complicado aun
cuando no hay que hacer comparaciones entre elementos ni nada de eso.
Queremos minimizar la cantidad de veces que un elemento hace el viaje memoria
secundaria memoria principal.
Acceder a un byte en memoria principal es un milln de veces ms rpido que acceder a
un byte en disco.
Acceso a byte en memoria 5 x 10-9 segundos (5 nanosegundos)
Transferir un byte de disco a memoria 2 x 10-8 segundos
Posicionamiento en el disco 5 x 10-3 segundos
Por lo general, cuanta ms informacin tenemos que guardar, necesitamos dispositivos
de memoria ms lentos. Hay que tratar de minimizar los accesos que se hacen a
memoria secundaria. Si puedo ahorrarme un acceso a memoria secundaria haciendo
100.000 accesos en memoria principal, estoy ganando
Tiempo de acceso dominado por el posicionamiento (ms que la transferencia en si misma):
conviene acceder a bloques de datos simultneamente.
A veces solo se puede acceder a los elementos en forma secuencial (por ejemplo en una
cinta)
Habitualmente puede haber jerarqua de niveles de memoria.
Cach RAM disco duro disco externo
Memoria virtual + manejo de memoria por parte del SO (caching) puede ser una buena
solucin si se usa un mtodo con buena localidad de referencia.
Memoria virtual: el so copia una pgina completa del disco en la ram y luego lo vuelve
a copiar al disco. Idealmente cuando se deja de usar (o sea cuando cree que se va a dejar
de usar, por ejemplo cuando se pide otra pgina.
Caching: se administra a travs de algoritmos de reemplazo en cach
Se requieren soluciones distintas.
Ordenacin-Fusin
Muchos mtodos hacen pasada sobre el archivo, dividindolo en bloques que entren en
memoria interna, ordenando esos bloques y luego fusionando.
El acceso secuencial resulta apropiado a este tipo de dispositivos.
Objetivo: minimizar el nmero de pasadas sobre el archivo.

Leo lo ms que puedo y lo ordeno. Un problema similar es el de la construccin de


ndices para la bsqueda. Las bsquedas de google, por ejemplo, se hacen sobre un
ndice. Voy indexando cosas ms chiquitas y luego las fusiono.
Mtodos de ordenacin para memoria secundaria
No siempre se encuentran con estos nombres (Sedgewick)
* Fusin Mltiple Equilibrada:
Supongamos que tenemos que ordenar los registros con los valores:
EJEMPLODEORDENACIONFUSION
Los registros (o sus claves) estn en una cinta y solo pueden ser accedidos secuencialmente.
En memoria hay solo espacio para un nmero constante pequeo de registros, pero
disponemos de todas las cintas que necesitemos (vamos a suponer capacidad 3 registros).
Primera pasada:
- Mientras haya elementos en la cinta de entrada
- Para i desde 1 hasta 3 hacer:
- leer 3 registros a la vez y escribirlos, ordenarlos en la cinta i

Segunda pasada:
- Mientras haya bloques de 3 en las 3 cintas hacer
- fusionar los 3 bloques armando uno de 9 en las cintas 4,5 y 6 alternadamente.

Etc.
Es un merge a tres vas (porque tengo tres cintas).
Log3 (N/M) es la cantidad de pasadas (con 6 cintas)
2p cintas logp (N/M)

Necesito memoria de tamao por lo menos p, por lo general las cintas son menos que el
tamao en memoria.
Complejidad (N registros, memoria interna de tamao M, fusiones a P vas)
- La primera pasada produce aprox N/M bloques ordenados.
- Se hacen fusiones a P vas en cada paso posterior, lo que requiere aprox logp (N/M)
pasadas.
Por ejemplo:
- Archivo de 200 millones de palabras
- 1 milln de palabras en memoria (cmo las ordenamos?)
- Fusin de 4 vas
- No ms de 5 pasadas.
Log4 200M/1M = 5
En realidad voy a leer de a un milln y los ordeno con alguno de los mtodos de
ordenamiento que vimos en memoria principal.
Tengo 3 cintas, leo 1/3 de N en cada una entonces lo cuento como una pasada aunque
sean 3 cintas.
Si tengo 4 cintas puedo poner todos los datos de la segunda pasada en la 4ta cinta.
Cuando termino hago una pasada por la 4ta y voy repartiendo los datos en las primeras
3.
P+1 cintas 2 logp (N/M)
Puedo usar dos cintas y dos cintas, entonces me quedara log2 (N/M) (cuanto ms chica
la base, ms grande el logaritmo, habr que ver qu conviene ms.
N/M bloques de tamao M
* Seleccin por sustitucin:
Idea: usar una cola de prioridad de tamao M para armar bloques pasar los elementos a
travs de una CP escribiendo siempre el ms pequeo y sustituyndolo por el siguiente.
Pero, si el nuevo es menor que el que acaba de salir, lo marcamos como si fuera mayor,
hasta que alguno de esos nuevos llegue al primer lugar de la CP
EJEMPLODEORDENACIONFUSION

Tamao de los bloques ordenados: 7,4,3,5,5,1


Propiedad: Para secuencias aleatorias, las secuencias creadas as son aproximadamente el
doble del tamao del heap utilizado.
Efecto prctico: ganamos una pasada sobre la secuencia (adems de pagar log M por
elemento en la primera pasada, pero es no es grave, ya que de la otra manera tambin
pagbamos N/M * M log M).
Armo un bloque de elementos ordenados de ms de tres elementos. Sigo hasta que vea
que el elemento que llega es ms chico que el anterior. Cuando eso pasa le hago una
marca para implicar que igualmente es ms grande, y lo bajo en el heap. Cuando todo lo
que me queda es barrado y no puedo sacar nada, armo un bloque nuevo. Saco las barras
(o las dejo, es lo mismo) y empiezo otra vez.
La barra es un bit ms pero hay lugar para es bit. En el peor caso me quedan bloques del
mismo tamao que antes.
El tamao esperado es bloques de tamao 2M (por lo menos una pasada menos en
promedio).
Me cuesta O(log M) sacar un elemento del heap N log M.
El costo en trminos de operaciones en memoria principal es el mismo, pero se gana
una pasada.
Ver ac el grfico de la hoja 31 y pasarlo a mano mejor
Cuando termino con la segunda cinta rebobino la segunda y la cuarta y empiezo a usar
la primera para escribir mergeando con la cuarta.
Cmo acomodar los N/M bloques inicialmente en las P cintas para que me calcen las
cosas perfecto es un clculo que se puede hacer a priori.
* Fusin polifsica:
Problema de los anteriores: gran cantidad de dispositivos necesarios: 2P o como mnimo P
+ 1 (a un costo de duplicar la cantidad de pasadas).
Cuando se tienen menos cintas se debe hacer lo siguiente:
- Distribuir los datos en todas las cintas menos una aplicando una estrategia de fusin
hasta el vaciado.

Comentario: Pasar esto despus

- cuando una cinta se vaca se puede rebobinar y usar como cinta de salida.

Se calcula armndose la matriz hasta que la suma de todas las columnas sea mayor a
N/M (idealmente empezando con la columna 1,0,0,0, etc.)
Uso una sola cinta de salida pero sin hacer la segunda pasada.
Secuencia ejemplo con 6 cintas:

Bsqueda/Diccionarios externa
Idea: poder encontrar una palabra entre un milln con dos o tres accesos a disco.
Ms parecidos a los mtodos de memoria principal que los mtodos de ordenamiento.
En Bases de datos aparece esta problemtica (tambin en versiones mucho ms elaboradas:
otros mtodos)
Acceso a pginas = bloques contiguos de datos a los que se puede acceder eficazmente (a
todos juntos): Modelo simplificado pero efectivo.
Mtodos:
* Acceso Secuencial indexado (ISAM)
Acceso secuencial puro. Ejemplo:
EJEMPLODEBUSQUEDAEXTERNA

Discos con 3 pginas de 4 registros cada una.

Qu pasa si queremos buscar X? Problemas conocidos.


Solucin: tener en cada disco un ndice que establezca qu claves pertenecen a las pginas
que estn en ese disco.
La primera pgina de cada disco es su ndice. El ndice dice cual es la mayor clave que se
encuentra en la pgina anterior.

Se puede acelerar ms con un ndice maestro, que dice qu claves estn en cada disco.
En el ejemplo anterior, el ndice maestro dira que el disco 1 contiene las claves <= E, el
disco 2 las claves <=O (pero no <E), el disco 3 las claves <=X (pero no <P)
El ndice maestro puede estar en memoria principal.
Problema de este mtodo: muy rgido, si va a haber inserciones y/o borrados.
Complejidad:
Bsqueda O(1)
Insercin O(n) pues puede implicar una reorganizacin completa.
Log2 1M = 20 tengo un AVL en memoria secundaria, con 20 accesos lo encuentro.
ISAM: acceso secuencial (prehistrico :P). Para buscar algo recorro secuencialmente.
Se podra mejorar con algo tipo bsqueda binaria pero ?
Los discos en general van a ser pocos. Una vez que acced al ndice necesito un acceso
ms (si no hay claves repetidas).
La primer mejora es hacer bsqueda binaria en los ndices. En lugar de acceder a P
discos, accedemos a log P. No va a cambiar mucho porque los discos no son muchos.
Puedo tener en memoria principal hasta qu letra va cada disco, entonces buscando en
memoria principal, que es casi gratis, se a qu disco acceder y despus solo me quedan
dos accesos al disco (al ndice del disco y a la pgina correspondiente).
* rboles B:
Son rboles balanceados: todas las hojas estn a la misma distancia de la raz.
Idea: acceder a una pgina de memoria por nivel.
Muchas claves por nodo/ mucha ramificacin.
Inventados por Bayer & McCreight (1970)
Variantes/Ejemplo/Antecedente: rboles 2-3-4
rboles 2-3-4
Los nodos pueden contener 1, 2 o 3 claves.

1 clave -> 2 enlaces: 2-nodos (posiblemente dos subrboles, las claves del izquierdo son
menores y las del derecho mayores)
2 claves -> 3 enlaces: 3-nodos (3 hijos y C1 < C2)
3 claves -> 4 enlaces: 4-nodos
Ejemplo de 3-nodo:

Claves EJEMPLODEBU

Insercin de S:

Para mantenerlo balanceado partimos el 4-nodo OPU en dos 2-nodos (O y U) y


mandamos la clave intermedia P hacia arriba.
Si el padre tambin es un 4-nodo:
Solucin 1: partirlo tambin a l e ir as hacia arriba.
Solucin 2: en el camino de descenso, ir partiendo todos los 4-nodos que encontremos.
Divisin de 4-nodos: Usa solo informacin local, se puede hacer en tiempo constante:

Secuencia de inserciones QUEDA

En el peor de los casos, todos son 2-nodo y es un rbol binario de bsqueda con todas
las hojas a la misma distancia de la raz => altura = log4 N
La insercin es siempre en la hoja que corresponda. Si es un 2-nodo o 3-nodo hay lugar
para un elemento ms, pero si la hoja ya es 4-nodo est saturado.
Agarramos la clave mayor (o la del medio?) la que queremos agregar se junta con
alguna de las dos que quedan y la otra la mandamos para arribaetc. Puede que
tengamos que partir a la raz y agregar un nuevo nodo.
Para no preguntar siempre si arriba hay lugar, cuando voy bajando si ya veo que hay
algo saturado lo parto antes (entonces arriba siempre va a haber lugar).
Cul es la diferencia entre partir al subir y partir al bajar? Pregunta de final.
Hay un costo constante por nivel y un nmero logartmico de ndices.
Al borrar se busca alguien para bajar de arriba?
Puntero a nodo a qu nodo es?

Comentario: Ac tengo como


muchas preguntas sin respuesta!!!

Complejidad de las operaciones:


Bsqueda O(log n)
Inserciones O(log n) (necesitan a lo sumo O(log N) divisiones de nodos)
Borrado: tambin se puede en O(log n) (Pensarlo!)
Problemas de implementacin:
Algoritmos con cierta complicacin. Ms complicacin proveniente del manejo de distintos
tipos de nodos.
Implementacin de rboles rojo-negros

Los rboles rojo-negros implementan los rboles 2-3-4 con rboles binarios, unos ejes
representan ejes del rbol original y los del otro color van a las claves del mismo nodo.
Volviendo a los rboles B:
Son similares a los anteriores, pero cada nodo puede tener hasta M-1 claves (o sea, hasta M
enlaces).
Para desplazarse al nodo siguiente hay que encontrar el intervalo apropiado de la clave
buscada y salir a travs del enlace correspondiente.
Similarmente a los rboles 2-3-4, es necesario dividir los nodos que estn llenos a lo
largo del camino: cada vez que se encuentra un k-nodo que es padre de un M-nodo, se lo
reemplaza por un (k+1)-nodo asociado a dos (M/2)-nodos.
La idea es que cada nodo corresponda a una pgina de disco.
Notar que eso incluye claves, datos y enlaces.
Notar tambin que M grande, implica mayor costo en cada nodo.
En realidad se puede distinguir entre nodos internos y hojas que no necesitan el espacio
para los ndices.
Hay muchas variantes y versiones distintas.
Son adecuados tambin para memoria principal. Muchas claves por nodo para que el
rbol sea petiso. No necesariamente son binarios y por lo general son mayores que
cuaternarios.
Los rboles B tienen un concepto de balanceamiento sper fuerte: todas las hojas estn
a la misma distancia de la raz. SIEMPRE.
Si agregamos algo ms lo agregamos hacia arriba (como una nueva raz). La insercin
es siempre en una hoja y la bsqueda siempre desde la raz.
Los verdaderos rboles B tratan de que en un nodo quepa lo mismo que cabe en una
pgina del disco. M es la medida de los nodos (etc)
Cuanto ms ancho el nodo, ms petiso el rbol. Suponemos que hacemos un acceso a
disco por nivel. O sea, tenemos que poder leer M-1 claves, M punteros y M-1
significados en un acceso a un nodo.

Comentario: Honestamente
estara bueno investigar un poco
sobre este tema porque no creo que
pudiera explicarlo.

Comentario: Esto me qued


algo contradictorio y confuso ?

Las operaciones entonces son en memoria principal


* Hashing Dinmico o Extensible:
A semejanza de los rboles B, los registros se almacenan en pginas que, cuando se llenan,
se dividen en dos partes.
Como en el acceso secuencial indexado, se mantiene un ndice al que se accede para
encontrar la pgina que contiene los registros que concuerdan con la clave.
Idea: Todos los elementos con el mismo valor de h, van a parar a la misma pgina de
memoria.
Si por causa de una insercin se llena una pgina, esta se divide en 2, los elementos van a
una u otra, dependiendo del valor de una nueva funcin de hash.
En la prctica, se va armando (y desarmando) un rbol de ndices, cuyas hojas apuntan al
archivo donde est el registro. Si el rbol de ndices cabe en memoria principal, entonces
con un solo acceso a disco, alcanza.
Es una especie de hbrido entre ISAM y rboles B con hashing.
Usamos hashing para hashear los elementos a pginas del disco.
Cuando divido una pgina, reacomodo los elementos y devuelvo la pgina que tena
antes.
Ejemplo: quiero insertar juan h(juan) me manda a una pgina llena, divido con h2
Cuando haga ahora h(juan) me va a mandar a una pgina que elimin y ya no es una
pgina. Entonces, en el instante en que divid la pgina en 2 me armo un rbol en
memoria principal que me dice como se fueron partiendo las pginas. Como la pgina
principal ya no existe pido h2(juan).

P
P1

P2

Es muy razonable suponer que el rbol entra en memoria principal. Si no cupiera, se


guarda en disco y se carga cuando se necesita (pero en general cabe).
Entonces: Pgina que se llena la parto, pgina que se vaca la devuelvo.
Tampoco exagero al punto de que cada vez que dos pginas hermanas sumadas tengan
P unifico, porque si no estoy cambiando todo el tiempo.
NOTA: No existen funciones de Hash que mantengan el orden (pregunta de final,
respuesta equivocada)
ALGO SOBRE COMPRESIN DE DATOS
Conflicto histrico:
Algoritmos tradicionalmente diseados para ahorrar tiempo y espacio.

Comentario: Completar este


grfico de Pg 33 de carpeta

Posibles conflictos:
- estructuras que son ms eficientes en trminos de tiempo que requieren ms espacio.
- estructuras que son eficientes en trminos de espacio pero requieren ms tiempo de
procesamiento.
A veces no hay conflicto: guardar la informacin en forma tal que ocupe el menor espacio
posible para que su transmisin lleve el menor tiempo posible.
Aunque cierto conflicto subsiste: si la informacin est muy bien compactada, puede
requerir tiempo de descompactacin.
Argumento: No hace falta comprimir ahora porque los dispositivos de almacenamiento
son muy baratos.
Contraargumentos: Al manejar grandes volmenes de informacin, los ahorros son ms
importantes Time is money
Compresin de archivos:
En general las tcnicas de compresin de archivos aprovechan la redundancia contenida en
los archivos.
Algoritmos que comprimen mejor la informacin pueden requerir ms tiempo y
viceversa.
Si en un mensaje no hay info redundante, por definicin no se puede comprimir.
Varios mtodos:
- Codificacin por longitud de series:
La redundancia ms simple que se puede encontrar son las largas series de caracteres
repetidos. Ej: AAAABBBAABBBBBCCCCCCCCDABCBAAABBBBCCCD
Reemplazamos cada repeticin por un solo ejemplar del carcter repetido, acompaado por
la cantidad de repeticiones:
4A3B2A5B8C1D1A1B1C1B3A4B3C1D
O mejor todava:
4A3BAA5B8CDABCB3A4B3CD
Variante para archivos binarios:
Almacenar simplemente la longitud de cada secuencia, sabiendo que los caracteres sern
alternantes. Es til si hay pocas series cortas:

Notar que, sabiendo que la longitud de cada lnea es de 51 pxeles, no hace falta almacenar
finales de lnea
Si se utilizan 6 bits para cada longitud, se necesitan 348 bits contra los 975 de la
representacin explcita.
Las impresoras guardan la info de los fonts en mapas de bits. Si definimos como
empieza, sabiendo que solo hay 0 y 1 basta con poner la longitud (ya se que cuando
termina 0 viene 1 y viceversa).
Bitmaps: matriz de tamao fijo.
Volviendo a archivos genricos:
Necesitamos representaciones separadas par los elementos del archivo y los de su versin
codificada (cmo distinguimos cual es la cantidad y cual el elemento?)
Supongamos que tenemos 26 letras y el espacio en blanco.
Una posibilidad es usar un carcter que no aparece como carcter de escape. Cada
aparicin indica que las siguientes son un par (longitud, carcter), y representamos una
longitud i con la i-sima letra.
Ejemplo usando la Q como escape: QDABBBAAQEBQHCDABCBAAAQDBCCCD
Notar que no codificamos secuencias de menos de 4 caracteres, ya que necesitamos al
menos 3 para codificar, esos 3 se llaman secuencia de escape.
Problema: qu hacemos si el carcter de escape s aparece?
Una solucin posible es representarlo con una secuencia de escape imposible:
Q<espacio> (sera imposible si el <espacio> corresponde al nmero 0).
Qu pasa si tratamos de comprimir un archivo ya comprimido?
Cmo hacemos para series ms largas que 26 elementos?
- Podemos usar varias secuencia de escape: QZAQYA significa 51 aes (26+25)
- Otra posibilidad: si se esperan secuencias largas, utilizar ms de un carcter para
codificar longitudes.
Cierre: Este mtodo no es muy til para archivos de texto, en los que los nicos caracteres
que aparecen en largas secuencias son los espacios.
La compresin es buena cuando hay secuencias de longitudes largas.
Con 6 bits podemos representar hasta el 64.
0002 5 estoy usando 6 bits para escribir 55.

Otra opcin con las 26 letras es arrancar usando la A para el 4 (ya que si tiene menos de
4 caracteres no uso el carcter de escape).
Si la Q tambin aparece en el texto, puedo buscar que sea un carcter poco comn y
seguir utilizndolo como carcter de escape, Cuando quiera representar una Q, la Q no
representa ningn nmero y la escribo como QQ.
Si queremos recomprimir algo ya comprimido, adems de que no tenemos secuencias
de ms de tres elementos y que el carcter que era frecuente ahora es muy frecuente.
Si represento secuencias ms largas (de nmeros) el espacio mnimo es ms grande.
- Cdigos de Huffman
La complejidad computacional de los cdigos de Huffman es n log n (para encontrar el
trie ptimo)
Codificacin: representar textos generados a partir de un alfabeto con secuencias de
caracteres de otro alfabeto:
Alfabeto E Alfabeto E - Texto E*
Cdigo: f: E E*
letras de un alfabeto en palabras del otro
f: E* E* palabras de un alfabeto en palabras de otro (por extensin)
Cualquier conjunto finito sirve como alfabeto {a,z} {0,1} {0,9} etc.
Ejemplo:
F(A) = 00001 F(B) = 00010 F(C)= 00011 (letras en palabras)
BABA = 00010 00001 00010 00001 (palabras en palabras)
Cdigos de longitud fija, ejemplo: ABRACADABRA
Representando cada letra con 5 bits, arrancando con el 00001 para la A, etc:
0000100010100100000100011000010010000001000101001000001
Decodificacin fcil: leer de a 5 bits y reemplazarlo por la letra correspondiente.
Si uso 5 caracteres para codificar voy leyendo de a 5 y busco en una tabla a qu carcter
corresponden esos 5 bits. Esto es un cdigo de longitud fija.
Como son 26 letras necesito mnimo 5 bits para que sea inyectiva.
Log2 T donde T es el tamao del alfabeto, es la cantidad de bits que necesito para
codificar
Cdigos de longitud variable:
Idea: por qu usar la misma cantidad de bits para representar caracteres muy frecuentes
que para caracteres muy raros?
Por ejemplo podemos usar A 0 B 1 R 01 C 10 D 11
ABRACADABRA = 0 1 01 0 10 0 11 0 1 01 0
15 bits en lugar de 55 qu pasa con los <espacio>? Ocupa ms pero sigue siendo ms
corto. En realidad todava es peor hay que incluir la tabla en el texto comprimido, pero
para textos grandes no molesta mucho)

Comentario: Ponerle una rayita


arriba

Cdigos prefijos:
Para evitar la necesidad de enviar separadores usamos Cdigos Prefijos: el cdigo de
ningn carcter es prefijo del cdigo de otro.
Ej: A 11 B 00 R 011 C 010 D 10
Hay una nica forma de decodificar el mensaje 1100011110101110110001111 y cualquier
mensaje
Esto sirve para que al no tener espacios no sea ambiguo, leo hasta que matchee con algo
en la tabla, cuando matchea con algo es eso, porque no existen prefijos.
En el ejemplo no hay forma de agregar otra letra sin que alguna se convierta en prefijo.
Si decido que la A se represente con un nico carcter, entonces voy a necesitar 6 bits
para representar los dems caracteres (ya que nada va a poder empezar con 1).
Puedo representar muchas de las letras ms frecuentes con 3 bits y las menos frecuentes
con ms de 5. La tabla se representa con un trie. En un cdigo de longitud fija, todas las
hojas van a estar a la misma distancia de la raz, no es as en los cdigos de longitud
variable.
Cualquier trie binario sobre el mismo conjunto de hojas es un cdigo y es un cdigo
prefijo (las definiciones siempre estn en las hojas es un cdigo prefijo para la
cantidad de hojas)
Ningn trie puede ser ms chico que log2 T pero s puede haber alguno donde la rama
ms corta sea menor.
De todos los rboles trie que tienen hojas que representan los caracteres de un alfabeto,
el mejor es el cdigo de Huffman?
El out de la tabla es un trie.
Representacin de cdigos prefijos:
Podemos usar un trie para representar el cdigo.
Cualquier trie con M nodos externos puede ser utilizado para codificar cualquier mensaje
con M caracteres diferentes: el cdigo de cada carcter se determina por el camino de la
raz al carcter.

Con el cdigo de la derecha, la cadena sera 011010011110111100110100 que es ms corta


por qu?
Cdigos prefijos ptimos:
Cdigo de Huffman (1952)
Dado el mensaje, calcular la frecuencia de aparicin de cada carcter.

Comentario: Chequear esto

Ejemplo: UNA CADENA SENCILLA A CODIFICAR CON UN NUMERO MINIMO DE


BITS

Construccin del trie:

Agarro los dos ms chicos (o dos de los ms chicos), los elimino y lo reemplazo por un
nodo que tiene la suma de sus frecuencias, lo voy construyendo de abajo para arriba (esto lo
hago con un heap)

Volviendo al ejemplo, se codifica con la siguiente secuencia, que tiene 228 bits en lugar de
los 300 que se utilizaran en la codificacin directa

El cdigo de Huffman da el mejor cdigo posible para cada texto. Si ya conozco las
frecuencias promedio para textos en castellano, puedo aplicar Huffman para textos en
castellano y voy a tener una buena compresin, pero no se si va a ser la mejor (si tengo
por ejemplo un personaje llamado Walter, la W va a aparecer mucho ms y la
compresin no va a ser tan buena, as como tampoco lo va a ser si lo aplico a un texto
en ingls.
El variante de la iteracin: es una funcin decreciente, siempre positiva, entonces el
algoritmo termina (cada vez tengo un nodo menos, saco 2 y pongo 1).
Parmetro: cantidad de caracteres del alfabeto que estoy codificando. Voy a demostrar
que si tiene un solo carcter es ptimo y que si funciona para alfabetos de tamao k-1
funciona para alfabetos de tamao k.
En lugar de longitud del texto codificado, vamos a hablar de: longitud ponderada de los
caminos externos: longitudes de las ramas, pesadas por el valor que est guardado en
la hoja. Esta es la longitud que va a tener el texto con ese trie.
Entonces, demostrar que el cdigo de Huffman es correcto, es demostrar que el rbol
tiene la mnima LPCE (externos, porque solo sumo las hojas)

Comentario: El dibujito de la
demo est en la carpeta, hoja 35)

Por qu este cdigo es mejor?


Definicin: La longitud ponderada del camino externo de un rbol es la suma, para todos
los nodos externos, del producto de su peso por la distancia a la raz.
Propiedad: La longitud del mensaje codificado es igual a la longitud ponderada del camino
externo del rbol de frecuencias de Huffman.
Teorema: ningn rbol con las mismas frecuencias en los nodos externos puede tener una
longitud ponderada del camino externo menor a la del rbol de Huffman.
Lema: Dado un cdigo, podemos reacomodar las hojas del rbol para que los dos caracteres
menos frecuentes sean hermanos y obtener un cdigo mejor o igual.
Demostracin del lema
-El menos frecuente (x) es la hoja ms lejana (si no lo es, hago un intercambio y obtengo un
cdigo mejor o igual
-El padre de x tiene otra hija h (si no la tiene, por qu no est ms arriba?)
-h tambin es una hoja ms lejana. Si esta ocupada por un nodo que no es el segundo menos
frecuente, sino por uno ms frecuente, podemos hacer un intercambio que mejorar el
cdigo.
Demostracin del teorema(por induccin en la cantidad de caracteres del alfabeto.
-Base: un carcter, trivial
-Paso inductivo:
* Sean x e y los caracteres menos frecuentes y f(x), f(y) sus frecuencias
* Sea el rbol T construido por el algoritmo de Huffman sobre el alfabeto en el que se
eliminan x e y reemplazndolos por un nuevo carcter z con frecuencia f(z)=f(x)+f(y)
* Por hiptesis inductiva, T es ptimo.
* La longitud ponderada del camino externo:
LPCE(T) = LPCE(T) f(x) f(y) < LPCE(T) f(x) f(y) = LPCE(T)
Absurdo porque supusimos que T era ptimo.
- Familia de mtodos ZL (Ziv-Lempel)
(usados actualmente para texto)
Propuestos por Abraham Lempel y Jacob Ziv en 1977. Tambin basados en la repeticin
pero de patrones ms complejos.
No necesita ni presuponer frecuencias ni hacer dos pasadas. Tambin utiliza tries.
Reemplaza secuencias completas por un puntero a una posicin del trie.
Utilizada en los mtodos GZip, etc.
Ej: 01010101 (1000 veces)
Voy leyendo y avanzo mientras sigo reconociendo el patrn, cuando el patrn cambia,
el conocido + el nuevo se convierte en un nuevo patrn conocido a buscar.
Mini-ejemplito:

Partimos el texto en bloques, ya visto+nuevo


carcter. Luego numeramos los bloques:

Reemplazamos cada bloque por un puntero al bloque ya visto y el nuevo carcter:

Podemos pensar todo como un TRIE:

Para descomprimir el texto tengo una estructura que apunta a los distintos bloques y
lneas para arriba (para ir subiendo el camino hacia la raz)
El trie no tiene que ser binario, puede ser cualquier alfabeto.
El trie va creciendo y con el mismo byte del puntero apunto cada vez a textos ms
largos.
Hay variantes que controlan el tamao del trie que se construye, por ejemplo, cuando
llega a un determinado tamao, lo guardo, lo reseteo, y empiezo devuelta. Otra es cortar
cuando se llega a determinada cantidad de caracteres (sin importar el tamao del trie).
Por ah un puntero es la posicin de una pgina de disco.
Hay formas ms eficientes en trminos de memoria (mientras se ejecuta) pero
comprimen menos.
Podes llegar a querer comprimir algo que no cabe completo en la memoria, por ejemplo
la biblia en 5 idiomas. Por ah es mejor usar 5 tries que uno.
OTRAS IMPLEMENTACIONES DE DICCIONARIOS
Skip Lists:
Diccionarios con listas encadenadas ordenadas. Muy simples pero ineficientes: O(n).
Busco hasta que lo encontr o me pas, n comparaciones en el peor caso
Buscamos una forma de avanzar ms rpido:

Si tengo tambin un puntero al siguiente del siguiente.


As, |n/2| + 1 comparaciones alcanzaran para una bsqueda.
Incluso podemos acelerarlo ms:

Si tengo punteros cada 4 entonces |n/4|+3 (a lo sumo tengo 3 elementos en el medio)


Y llevarlo al lmite:

En el lmite, cada 2i-esimo nodo posee una referencia al nodo 2i posiciones ms adelante en
la lista.
El nmero total de referencias es el doble.
Pero como mximo se examinan O(log (n)) nodos durante una bsqueda.
El problema principal es la rigidez en el caso dinmico (dificultad para mantenerla en el
caso de borrados)
Podramos tener log n niveles, se parece a una bsqueda binaria. Tenemos una
estructura que nos permite hacer bsquedas estticas con un costo logartmico, pero
esto me ocupa ms memoria.
Hay algunos nodos que pueden tener log n niveles. La mitad de los nodos tienen un
puntero.
1 n/2 + 2 n/4 + 3 n/8= n i=1 hasta log n i/2i = n2 (la serie converge a 2)
La insercin y el borrado son complicados (es completamente rgida)
En el problema anterior de los nodos son de nivel 2, de nivel 2 y 1/2i son de nivel 2i
Podemos aleatorizar o randomizar el requerimiento, y asignar el nivel de cada nodo
probabilsticamente, por ejemplo, subindole el nivel mientras una moneda siga saliendo
cara.

Costo de bsqueda: el anlisis completo puede ser complicado, pero intuitivamente es


O(log n) en promedio (pero sin hacer hiptesis probabilsticas sobre el input).
Con una moneda cargada se pueden mejorar las constantes si p(cara) = 1/e.

Puede ser que tenga un elemento de nivel 20 en una lista de 100, la probabilidad es de
1/1020
Para que pueda haber algn elemento de nivel 20
La probabilidad de que salgan 19 caras seguidas aumenta a medida que voy agregando
elementos
Tambin podra ser que en todas las veces haya salido seca en el primer intento.
El lugar donde va el nuevo elemento est dado por el orden. El nivel depende de la
moneda.
Se puede pensar como que cada nivel es una lista distinta (aunque comparten los
mismos nodos de informacin)
Si queremos optimizar la constante, la moneda que tenemos que usar no es balanceada,
si no que la probabilidad de que salga seguir tirando tiene que ser de 1/e, entonces, la
probabilidad de subir de nivel es un poco ms baja.
Para borrarlo, lo borro de todas las listas en las que est.
El peor caso est dado por las tiradas de la moneda y no por el input.
ABB ptimos
Si supiramos las frecuencias de acceso a cada elemento podramos armar un rbol en el
que los elementos ms accedidos estn ms cerca de la raz.
A qu nos hace acordar esto?
En tiempo O(n2) se puede construir el rbol ptimo.
Problemas:
- la rigidez
- desconocimiento a priori de las probabilidades (frecuencias) de acceso).
- variabilidad en el tiempo de las frecuencias de acceso
rboles binarios de bsqueda a secas. El rbol ptimo, minimiza la longitud ponderada
de todos los caminos.
Si se puede modificar el rbol a medida que avanzo puede haber un rbol mejor.
Estructuras de datos adaptativas (self adjusting): Se modifican incluso a partir de
operaciones que no modifican la estructura de datos de alto nivel (por ejemplo cuando
busco)
Splay Trees
Idea: tratar de tender todo el tiempo al ABB ptimo (para ese momento)
Estructuras auto-ajustantes:
- cada vez que accedo a un elemento lo subo en el rbol, llevndolo a la raz a travs de
rotaciones tipo AVL.
No funciona a travs de rotaciones simples entre el elemento accedido y su padre hasta
llegar a la raz.
Funciona con Splaying (Sleator & Tarjan, 1985)
Son ms simples de implementar que los rboles balanceados (no hay que verificar
condiciones de balanceo).

Sin requerimientos de memoria adicionales (no hay que almacenar factores de balanceo ni
nada parecido).
Muy buena performance en secuencias de acceso no uniformes.
Si bien no podemos garantizar O(log n) por operacin, si podemos garantizar O(m log n)
para secuencias de m operaciones. Una operacin en particular podra requerir tiempo O(n).
En general cuando una secuencia de M operaciones toma tiempo O(M f(N)) se dice que el
costo amortizado en tiempo de cada operacin es O(f(n)). Por lo tanto, en un splay tree los
costos amortizados por operacin son O(log N)
Ms an (Teorema de Optimalidad Esttica): asintticamente, los ST son tan eficientes
como cualquier ABB fijo.
Por ltimo (Conjetura de la Optimalidad Dinmica): asintticamente, los ST, son tan
eficientes como cualquier ABB que se modifique a travs de rotaciones.
Splaying:
Si accedemos a la raz del rbol, no hacemos nada.
SI accedemos a k y el padre de k es la raz, hacemos una rotacin simple.
Si accedemos a k y el padre de k no es la raz, hay dos casos posibles (y sus especulares):
rotacin zig-zag y rotacin zig-zig
Como efecto del splaying, no solo se mueve el nodo accesado a la raz, sino que todos los
nodos del camino desde la raz hasta el nodo accesado se mueven aproximadamente a la
mitad de su profundidad anterior, a costa de que algunos pocos nodos bajen como mximo
dos niveles en el rbol.
Rotacin Zig-Zag

Rotacin Zig-Zig

Acceso al nodo d

Amortizado: Promedio aritmtico entre todas las operaciones puede haber operaciones
caras, pero de alguna manera se compensan con otras baratas.
Un Popall cuesta x, para hacer un popall tengo que hacer x push (que son ms baratos)
El costo (asintticamente) no es mayor que una constante multiplicada por cualquier
ABB fijo.
Insercin y borrado:
Para insertar, hacemos como siempre: buscamos el lugar donde correspondera insertar y
efectuamos las rotaciones resultantes de esa bsqueda. El elemento insertado queda
entonces en la raz.
Para borrar un elemento de un st se puede proceder de la siguiente forma: se realiza una
bsqueda del nodo a eliminar, lo cual lo deja en la raz del rbol. Si esta es eliminada, se
obtienen dos subrboles Sizq y Sder. Se busca el elemento mayor en Sizq, m, que pasa a ser
su nueva raz. Como m era el elemento mayor, no tena hijo derecho, por lo que se cuelga
Sder como subrbol derecho y Sizq-m como subrbol izquierdo, como lo que termina la
operacin de eliminacin
(Puedo poner de raz el ms chico de la derecha, o el ms grande de la izquierda)
Listas Auto-ajustantes
Volvemos a la implementacin de diccionarios con listas, pero listas especiales: el
elemento accedido se mueve a la raz. Poltica Move-to-front (MTF)
Teorema: el costo total para una secuencia de m operaciones en una lista MTF es a lo sumo
el doble que el de cualquier implementacin del diccionario usando listas (Sleator &Tarjan
1985)

Comentario: Cuantas palabras


raras.

Otra forma de decirlo: MTF es 2-competitivo. Esto es un ejemplo de Anlisis de


Competitividad: medir algoritmos comparando su costo amortizado en el peor caso con el
del (posiblemente imposible de implementar) algoritmo ptimo.
El anlisis de competitividad se usa especialmente para problemas on-line, que son
problemas en los que hay que tratar de optimizar algo, sin conocer completamente los datos
de entrada.
Lo busco gratis lo elimino y lo pongo delante de todo O(1), pago a lo sumo el
doble

Temas vistos en las tericas:


Especificacin clase 1:
- Introduccin de la materia
- Repaso de lgica
- Definicin de la herramienta que se va a usar para especificar (TAD)
- Descripcin formal de dos de los tipos bsicos (bool y nat)
Especificacin clase 1:
- Repaso de nuestra definicin de lgica
- Definicin de otros tipos
- Elementos estructurales de un TAD
- Metodologa de gua para la construccin de un TAD
Induccin estructural:
- se generaliza el mtodo conocido desde lgebra 1
Pilas, colas y memoria dinmica:
- Pilas y colas con arreglos y sus limitaciones
- Memoria dinmica
- Colas en base a listas enlazadas
Complejidad clase 1
- Concepto naif de costo temporal de un algoritmo
- Formalizacin de varias nociones de complejidad de un algoritmo usando clases de funciones.
- Ejemplo de uso
Complejidad clase 2
- Aritmtica de rdenes de complejidad
- Ecuaciones de recurrencia
- Mtodo de sustitucin
- Mtodo de rbol de recursin
- Mtodo maestro: su uso
Diseo jerrquico de tipos
rboles de bsqueda 1 y 2
- Diccionarios en base a arreglos y secuencias y sus limitaciones
- Introduccin a las estructuras arbreas
- ABBs
- Intro a los AVLs
- Insercin y borrado en AVL (rotaciones)
Tablas de hash clase 1 y 2
Bsqueda Digital, Tries, etc.
Colas de prioridad, heap
Ordenamiento (Sorting)
- Selection Sort
- Insertion Sort
- Merge Sort
- Heap Sort
- Quick Sort
- rboles de decisin

Divide and conquer


- Calculo de costos
- Algoritmo de Karatsuba
Eliminacin de la recursin y transformacin de programas:
- Inmersiones de rango y de dominio: tipos especficos de generalizacin de funciones que
permiten obtener versiones ms eficientes(a veces reduciendo la complejidad, a veces slo las
constantes, pero siempre preservando la correccin)
- Plegado y desplegado (tcnica de transformacin muy til)
- Problemas de la recursin y como eliminarla:
- de las funciones recursivas a la cola
- de las funciones recursivas lineales no a la cola
- como transformar algunas recursiones mltiples en anidadas
-Como eliminar la recursin de algunas recursiones anidadas.
-Cuando hay que obtener una generalizacin a veces la deducimos y otras proponemos y luego
demostramos.
- tcnicas varias de transformacin.
(EN ESTA CLASE HAY BIBLIOGRAFIA ULTIMA DIAPO)
Sorting y Searching en memoria secundaria:
- Sorting: Mtodos de ordenacin-fusin:
-Fusin Mltiple equilibrada
- Seleccin por sustitucin
- Fusin Polifsica
- Searching (bsqueda/diccionarios):
- Acceso secuencial indexado (ISAM)
- rboles B (rboles 2-3-4, implementacin rojo-negro)
- Hashing extensible
Algo sobre compresin de datos:
- Codificacin por longitud de series
- Cdigos de Huffman
- Familia de mtodos ZL(Ziv Lempel)
Otras implementaciones de diccionarios:
- Skip Lists
- ABB ptimos
-Splay Trees
-Listas autoajustantes

S-ar putea să vă placă și