Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Clases de Complejidad Por EOR PDF
Clases de Complejidad Por EOR PDF
Departamento de Ingeniería
Abancay - 2013.
Contenido
Introducción ....................................................................................................................................... 3
Asíntotas........................................................................................................................................... 16
Ecuaciones de Recurrencia............................................................................................................... 23
Bibliografía ...................................................................................................................................... 33
Pág. 2
Complejidad de los algoritmos recursivos
Introducción
Por lo tanto el presente Manual nos ha de permitir medir de alguna forma el costo
(en función del tiempo) que consume un algoritmo para encontrar la solución y nos
problema.
Eficiencia y complejidad
Simplicidad
Uso eficiente de los recursos:
o el espacio (memoria que utiliza)
o y el tiempo (lo que tarda en ejecutarse).
Eficiencia temporal
Principio de Invarianza
Dado un algoritmo y dos implementaciones suyas I1 e I2, que tardan T1(n) y T2(n)
segundos respectivamente, el Principio de Invarianza afirma que existe una constante real
c > 0 y un número natural n0 tales que para todo n ≥ n0 se verifica que T1(n) ≤ cT2(n).
Con esto podemos definir sin problemas que un algoritmo tarda un tiempo del orden
de T(n) si existen una constante real c > 0 y una implementación I del algoritmo que tarda
menos que cT(n), para todo n tamaño de la entrada.
Dos factores a tener muy en cuenta son la constante multiplicativa y el n0 para los que
se verifican las condiciones, pues si bien a priori un algoritmo de orden cuadrático es
mejor que uno de orden cúbico, en el caso de tener dos algoritmos cuyos tiempos de
ejecución son 106n2 y 5n3 el primero sólo será mejor que el segundo para tamaños de la
entrada superiores a 200.000.
De los tres casos el que consideramos de mayor importancia es el caso peor, por las
siguientes razones:
Es el más informativo (el caso mejor suele ser trivial).
Nos permitirá acotar superiormente el consumo de recursos: sabremos que nuestro
programa
no consumirá más de lo estimado.
Es más fácil de calcular que el caso medio.
Ejemplo
Sea A una lista de n elementos A1, A2, A3, ... , An. Ordenar significa permutar estos
elementos de tal forma que los mismos queden de acuerdo con un orden preestablecido.
Ascendente A1 <=A2 <=A3 ..........<=An
Descendente A1 >=A2 >=........>=An
Caso peor: Que el vector esté ordenado en sentido inverso.
Caso mejor: Que el vector esté ordenado.
Caso medio: Cuando el vector esté desordenado aleatoriamente
Son las operaciones básicas, asignaciones a variables, los saltos, llamadas a funciones y
procedimientos, retorno de ellos, etc.
Las comparaciones lógicas y el acceso a estructuras indexadas, como los vectores y
matrices. Cada una de ellos cuenta como 1 OE.
Por lo tanto al medir el tiempo, siempre lo haremos en función del número de OEs,
para un tamaño de entrada dado.
La siguiente lista presenta un conjunto de reglas generales para el cálculo del número de
OE, siempre considerando el peor caso.
3ro Caso medio: En el caso medio, el bucle se ejecutará un número de veces entre 0 y
n–1, y vamos a suponer que cada una de ellas tiene la misma probabilidad de suceder.
Como existen n posibilidades (puede que el número buscado no esté) suponemos a priori
que son equiprobables y por tanto cada una tendrá una probabilidad asociada de 1/n. Con
esto, el número medio de veces que se efectuará el bucle es de:
n 1
1 n 1
i n
i 0 2
Tenemos pues que n 1 2
T(n) 1 2 ( 4 2 ) 4 2 1 3n 7 OE
i 1
En la práctica no se trabaja con T(n) sino con funciones que clasifiquen estas
funciones acotando su valor asintóticamente. Por ejemplo: si el T(n) de un algoritmo es:
10n 2
T(n) 2n
3
Diremos que T(n) pertenece O(n2) como lo veremos posteriormente en el tema de
asíntotas.
Ejercicios:
1. Read(n)
2. s=0
3. i=1
4. While(i<=1) do
5. s=s+1
6. i=i+1
7. End(While)
8. Write(n,s)
a. Mejor Caso: En el mejor de los casos no entra en el bucle While por lo cual se
ejecutan las siguientes operaciones elementales.
t(n) = 5 OE
1. read(n) 1 OE
2. s=0 1 OE
3. i=1 1 OE
4. while(i<=1) do 1n +1 OE (n vueltas + 1 evaluación de salida)
5. s=s+1 2n OE
6. i=i+1 2n OE
7. end(while)
8. write(n,s) 1 OE
t(n) = 5n+5 OE
c. Caso medio: En el caso medio como se explico en el ejercicio 1, los bucles se dividen
entre la mitad de vueltas que den los bucles, por lo cual se tiene:
1. Read(n) 1 OE
2. s=0 1 OE
3. i=1 1 OE
4. While(i<=1) do 1n/2+1 OE
5. s=s+1 2n/2 OE
6. i=i+1 2n/2 OE
7. End(While)
8. Write(n,s) 1 OE
t(n) = 5n/2+5 OE
1. Read(n)
2. s=0
3. i=1
4. While(i<=1) do
5. s=s+1
6. i=i+1
7. End(While)
8. Write(n,s)
a. Mejor Caso: En el mejor de los casos no entra en el bucle While por lo cual se
ejecutan las siguientes operaciones elementales.
t(n) = 5 OE
1. read(n) 1 OE
2. s=0 1 OE
3. i=1 1 OE
4. while(i<=1) do 1n +1 OE (n vueltas + 1 evaluación de salida)
5. s=s+1 2n OE
6. i=i+1 2n OE
7. end(while)
8. write(n,s) 1 OE
t(n) = 5n+5 OE
c. Caso medio: En el caso medio como se explico en el ejercicio 1, los bucles se dividen
entre la mitad de vueltas que den los bucles, por lo cual se tiene:
1. Read(n) 1 OE
2. s=0 1 OE
3. i=1 1 OE
4. While(i<=1) do 1n/2+1 OE
5. s=s+1 2n/2 OE
6. i=i+1 2n/2 OE
7. end(while)
8. Write(n,s) 1 OE
t(n) = 5n/2+5 OE
En adelante consideraremos solo el caso peor por ser de mayor representatividad para
nuestros fines.
Si en un inicio n=32 y el bucle termina dando 5 entradas, entonces la relación que existe
entre 32 y 5 es: Log 2 32=5, por consiguiente cada instrucción del ciclo se ejecuta un
número de veces igual al logaritmo en base dos de n. Por lo tanto:
1. Read(n) 1 OE
2. S=0 1 OE
3. While n>1 do (Log2n)+1 OE
4. S=S+1 2*(Log2n) OE
5. n=n/2 2*(Log2n) OE
6. End(While)
7. Write (n,S) 1 OE
t(n) = 5 Log2n+3
1. Read(n)
2. S=0
3. While n>1 do
4. S=S+1
5. n=n/3
6. End(While)
7. Write (n,S)
Aquí la variable controladora se divide por 3 dentro del ciclo. Damos un valor
arbitrario a n para ver su comportamiento n=81, haciendo el seguimiento tenemos. En la
primera pasada n=27, en la segunda n=9, el la tercera n=3 y en la cuarta sale con n=1 y
finaliza el bucle. Ahora la relación que existe entre n=81 y 4 vueltas del bucle es:
Log381=4.
Ahora si analicemos nuestro algoritmo línea por línea, incluyendo las vueltas del
bucle, obtenemos:
1. Read(n) 1 OE
2. S=0 1 OE
3. While n>1 do (Log3n)+1
4. S=S+1 2*(Log3n)
5. n=n/3 2*(Log3n)
6. End(While)
7. Write (n,S) 1 OE
t(n) = 5 Log3n + 3
Nota: Para calcular el número de Operaciones Elementales del bucle FOR hacemos la
conversión a su equivalente bucle WHILE:
1. i=1 1OE
2. While i<=n do 1OE
1. for i:=1 to n do 3. Begin
2. begin 4. i:=i+1; 2OE
3. end; 5. End;
Como vemos una aproximada conversión en cuanto a su complejidad del bucle FOR al
WHILE es 4 OE por lo cual en adelante contabilizaremos a todo bucle FOR como 4 OE.
1. n:=Length(lista); 2 OE
2. for i:=0 to n-1 do (4+1)n +1OE multiplicado por n vueltas
3. begin
4. for j:=0 to n-1 do ((4+1)n+1) n OE se multiplican ambos bucles
5. begin
6. if lista[i]>lista[j] then 3n2 OE
7. begin
8. aux:=lista[i]; 2 n2 OE
9. lista[i]:=lista[j]; 3 n2 OE
10. lista[j]:=aux; 2 n2 OE
11. end;
12. end;
13. end;
t(n) = 15n2+6n+3
Asíntotas
Para cada uno de estos conjuntos se suele identificar un miembro f(n) que se
utiliza como representante de la familia, hablándose del conjunto de funciones “g” que
son del orden de "f(n)", denotándose como:
O(f(n)) esta formado por aquellas funciones g(n) que crecen a un ritmo menor o igual que
el de f(n).
De las funciones “g” que forman este conjunto O(f(n)) se dice que “están
dominadas asintóticamente” por “f”, en el sentido de que para n suficientemente grande,
y salvo una constante multiplicativa “k”, f(n) es una cota superior de g(n).
Las siguientes propiedades se pueden utilizar como reglas para el cálculo de órdenes de
complejidad. Toda la maquinaria matemática para el cálculo de límites se puede aplicar
directamente:
g(n) IN O(f(n))
O(f(n)) = O(g(n))
g(n) IN O(f(n))
O(f(n)) es superconjunto de O(g(n))
Ejemplo:
Para demostrar que f(n) no es de orden cuadrático basta tener en cuenta que:
0,01𝑛3
lim = lim 0.01𝑛 = ∞
𝑛→∞ 𝑛2 𝑛→∞
2. Sea 𝑓 𝑛 = 𝑛2 + 𝑛 − 5 y 𝑔 𝑛 = 𝑛3 + 2𝑛 − 2
′
𝑓 𝑛 𝑛 2 +𝑛−5 𝑛 2 +𝑛−5 ∞ 2𝑛+1 ′ 2 2
Entonces lim𝑛→∞ = 𝑔(𝑛) = 𝑛 3 +2𝑛−2 = =∞= = 6𝑛 = ∞ = 0
𝑛 3 +2𝑛−2 ′ 3𝑛 2 +2 ′
𝑔 𝑛 𝑂(𝑓 𝑛 )
𝑂 𝑓 𝑛 𝑒𝑠 𝑆𝑢𝑛𝑐𝑜𝑛𝑗𝑢𝑛𝑡𝑜 𝑑𝑒 𝑂 𝑔 𝑛
3. Sea 𝑓 𝑛 = 𝑛2 + 𝑛 − 5 y 𝑔 𝑛 = 𝑛2
′
𝑓 𝑛 𝑛 2 +𝑛−5 ∞ 𝑛 2 +𝑛−5 2𝑛+1 ′ 2
Entonces lim𝑛→∞ 𝑔(𝑛) = =∞= = =2=1
𝑛2 𝑛2 ′ 2𝑛 ′
𝑔 𝑛 𝑂(𝑔 𝑛 )
𝑂 𝑓 𝑛 = 𝑂 𝑔 𝑛
Para demostrar que f(n) es de orden cuadrático basta tener en cuenta que:
Órdenes de complejidad
O(n log n)
El caso base, que maneja una entrada simple que puede ser resuelta sin una
llamada recursiva
La parte recursiva, que contiene una o más llamadas recursivas al algoritmo,
donde los parámetros están en un sentido más cercano al caso base, que la
llamada original.
0! = 1
n! = n * (n-1)! si n>0
Las funciones recursivas finales suelen ser más eficientes (en la constante
multiplicativa en cuanto al tiempo, y sobre todo en cuanto al espacio de memoria) que
las no finales. (Algunos compiladores pueden optimizar automáticamente estas
Ecuaciones de Recurrencia
Para resolver ese tipo de ecuaciones hay que encontrar una expresión no recursiva
de 𝑡 𝑛 . (En algunos casos no es tarea fácil.)
El problema de las torres de Hanoi, tiene una solución recursiva que se basa en
mover n − 1 discos de A a B, luego el más grande de A a C y finalmente los n − 1 en B
hacía C. Si definimos T (n) cantidad de movimientos de disco necesarios para resolver el
problema de las torres de Hanoi con n discos, obtenemos:
t(n) = 2 t(n − 1) + 1
mover n − 1 discos como si fuese el mismo problema de las torres de Hanoi (notar que
sólo cambia a torre intermedia, la solución es efectivamente la misma).
1. Primer método: Suponer una solución f(n), y usar la recurrencia para demostrar que
t(n) = f(n). La prueba se hace generalmente por inducción sobre n.
n t(n)+1
1 2
2 4
3 8
4 16
Cuadro 2: Algunos valores de t(n)+1
t(n) = 2 t(n−1) + 1 es
t(n) = 2n − 1.
t(n + 1) = 2n+1 − 2 + 1
t(n + 1) = 2n+1− 1
Desde (2) a (3) se utiliza la hipótesis y desde ahí se llega directamente al resultado
esperado.
Es importante tener en cuenta que cualquier solución que encontremos con los
métodos expuestos a continuación pueden ser verificados utilizando esta misma
forma.
2. Segundo método: Sustituir las recurrencias por su igualdad hasta llegar a cierta
𝑡(𝑛 0 ) que sea conocida.
Ejemplo:
𝐶1 , 𝑆𝑖 𝑛 ≤ 1
𝑡(𝑛) = 𝑡
(𝑛−1) + 𝐶2 , 𝑆𝑖 𝑛 > 1
𝑡(𝑛−1) = 𝑡(𝑛−2) + 𝐶2
𝑡(𝑛−2) = 𝑡(𝑛−3) + 𝐶2
𝑡(𝑛−3) = 𝑡(𝑛−4) + 𝐶2
Luego de ello sustituimos sus equivalentes en (I), hasta obtener el k-esimo termino
de las sustituciones.
𝑡(𝑛) = 𝑡(𝑛−1) + 𝐶2
𝑡(𝑛) = 𝑡(𝑛−2) + 𝐶2 + 𝐶2
𝑡(𝑛) = 𝑡(𝑛−2) + 2𝐶2
𝑡(𝑛) = 𝑡(𝑛−3) + 𝐶2 + 2𝐶2
𝑡(𝑛) = 𝑡(𝑛−3) + 3𝐶2
⋮
𝑡(𝑛) = 𝑡(𝑛−𝑘) + 𝑘𝐶2 (II)
A) Primera forma
Un ejemplo muy conocido son los números de Fibonacci, cuya ecuación es:
𝑡(𝑛) = 𝑡 𝑛 −1 + 𝑡 𝑛 −2
1+ 5 1− 5
λ1 = , λ2 =
2 2
𝑛 𝑛
1 1+ 5 1− 5
𝑡𝑛 = −
5 2 2
B) Segunda Forma
𝑘 ≥ 0.
Teorema: La solución para la ecuación 𝑡 𝑛 = 𝑡 𝑛−1 + 𝑓 𝑛 es:
𝑡𝑛 =𝑡𝑘 + 𝑓 𝑖 ∀𝑛 ≥ 𝑘
𝑖=𝑘+1
𝑡 𝑛 = 𝑡 𝑘−1 + 𝑓 𝑛 𝑡 𝑛 − 𝑡 𝑘−1 = 𝑓 𝑛
En esta ecuación es una variable muda y puede escribirse como:
𝑡 𝑖 − 𝑡 𝑖−1 = 𝑓 𝑖
𝑛 𝑛
(𝑡(𝑖) − 𝑡(𝑖−1) ) = 𝑓𝑖
𝑖=𝑘+1 𝑖=𝑘+1
𝑡𝑛 −𝑡𝑘 = 𝑓𝑖
𝑖=𝑘+1
Obteniendo finalmente:
𝑛
𝑡𝑛 =𝑡𝑘 − 𝑓𝑖
𝑖=𝑘+1
𝑡 𝑛 = 𝑡 𝑛−1 + 𝑛 − 1, 𝑡 0 = 0
C) Tercera forma
𝑛
𝑡 𝑛 = 𝑎𝑛−𝑘 𝑡 𝑘 + 𝑎𝑛−𝑘 𝑓 𝑖 ∀ 𝑛 ≥ 𝑘
𝑖=𝑘+1
𝑡 𝑛 𝑎𝑡 𝑛−1 𝑓 𝑛
= + 𝑛
𝑎𝑛 𝑎𝑛 𝑎
𝑎𝑡 𝑛 −1 𝑡 𝑛 −1 𝑡𝑛
Notamos que = . Si definimos 𝑔 𝑛 = 𝑎𝑛
la ecuacion resultante es:
𝑎𝑛 𝑎 𝑛 −1
𝑓𝑛
𝑔 𝑛 =𝑔 𝑛−1 +
𝑎𝑛
Usando el teorema propuesto obtenemos:
𝑛
𝑓𝑖
𝑔 𝑛 =𝑔 𝑛−1 +
𝑎𝑖
𝑖=𝑘+1
𝑛
𝑡𝑛 𝑡𝑘 𝑓𝑖
𝑛
= 𝑘 +
𝑎 𝑎 𝑎𝑖
𝑖=𝑘+1
𝑛
𝑡 𝑛 = 2𝑡(𝑛−1) + 1, 𝑡 0 =0
La solución es:
𝑛
𝑛
𝑡 𝑛 = 2 .𝑡 0 + 2𝑛−𝑖
𝑖=1
𝑛
𝑡 𝑛 =2 −1
D) Cuarta Forma
𝑘
una solución exacta para 𝑛 = 𝑏 . Para simplificar el resultado, consideraremos
𝑡 1 como condición inicial conocida.
como solución:
𝑙𝑜𝑔 𝑏 (𝑛)
𝑙𝑜𝑔 𝑏 (𝑛)
𝑡 𝑛 =𝑎 𝑡(1) + 𝑎𝑙𝑜𝑔 𝑏 𝑛 −𝑖
𝑓 𝑏𝑖 ∀ 𝑛 = 𝑏𝑘 , 𝑘 ≥ 1
𝑖=1
𝑡 𝑛 𝑘 = 𝑎𝑡 𝑏𝑘 𝑏 + 𝑓(𝑏 𝑘 )
𝑔 𝑘 = 𝑎𝑔 𝑘−1 +𝑓 𝑏𝑘
𝑡 𝑛 = 2𝑙𝑜𝑔 2 𝑛
𝑖=1
𝑡 𝑛 = 2𝑙𝑜𝑔 2 𝑛
𝑙𝑜𝑔2 𝑛
𝑡 𝑛 = 𝑛𝑙𝑜𝑔2 (𝑛)
𝑡 𝑛 =𝑡 1 + 1
𝑖=1
𝑡 𝑛 = 1 + 𝑙𝑜𝑔2 (𝑛)
Bibliografía