Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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.
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.
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)
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
r1 : t x args -> T
...
rm : t x args -> T
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.
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
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;
};
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.
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
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)
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)
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.
en la definicin.
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
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.
se explica con
se explica con
Conj[nat]
Ttads
SecuenciaDeNat
Se representa con
se explica con
Conj[nat]
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.
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.
* 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
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.
^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
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.
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)
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.
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.
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
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:
para
Esta manera de definir, de hecho considerada algortmica, es usual en Matemtica discreta.
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 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
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.
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?
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
), es el bit ms significativo,
), 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.
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.
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.
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:
Observadores bsicos
vaca?: colaPrior(,<
) bool
) c
(~vaca?( c ))
) c colaPrior(,< )
(~vaca?( c ))
Generadores
vaca: colaPrior(,<
encolar: colaPrior(,<
) colaPrior(,< )
Otras Operaciones
=colaPrior : colaPrior(,<
) colaPrior(,< ) bool
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)
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):
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
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.
Considerando que:
Deducimos que:
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.
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.
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 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
Comentario: Lo acabo de
inventar
Nombre original
Complejidad
Memoria Mtodo
Ordenamiento de burbuja
Bubblesort
O(n)
O(1)
Intercambio
Cocktail sort
O(n)
O(1)
Intercambio
Selection Sort
O(n)
O(1)
Intercambio
Insertion sort
O(n)
O(1)
Insercin
Bucket sort
O(n)
O(n)
No comparativo
Counting sort
O(n+k)
O(n+k)
No comparativo
Merge sort
O(n log n)
O(n)
Mezcla
O(n log n)
O(n)
Insercin
Pigeonhole sort
O(n+k)
O(k)
Radix sort
O(nk)
O(n)
Distribution sort
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
Selection sort
O(n)
O(1)
Seleccin
Heapsort
O(n log n)
O(1)
Seleccin
Smoothsort
O(n log n)
O(1)
Seleccin
Quicksort
O(log n)
Particin
Ordenamiento rpido
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
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
La solucin dice que a lo sumo tenemos que comparar algunos puntos. Entonces:
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:
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:
-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:
Definicin
Dada una funcin f del tipo
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.
(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.
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
- 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
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:
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?
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.
P
P1
P2
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)
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.
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)
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:
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.
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)