Complejidad y Análisis de Algoritmos
Complejidad y Análisis de Algoritmos
Lenguajes y Ciencias
de la Computación
E.T.S.I. Informática
1
¿Qué vamos a hacer? - Guia
❑ “Estudiar como se estudia” la complejidad de los
algoritmos.
⚫ ¿Cómo?
⚫ Ejemplos y problemas
❑ Algoritmia elemental.
❑ Notación asintótica.
❑ Ecuaciones de recurrencia.
❑ Clases de complejidad
Algoritmia Elemental
❑ Recursos que requiere un algoritmo.
E/S
ALGORITMO
Una ó más Una ó más
entradas salidas
Algoritmia Elemental
❑ Diferentes algoritmos para un mismo problema. ¿Cual utilizar?
❑ Factores: facilidad de programación, claridad, robustez, .... , y por
supuesto el criterio empresarial de eficiencia: relación entre los
recursos consumidos y los productos conseguidos.
Algoritmo Recursos (Var a: vector [1..n] de
< tipo_elemento>; x : entero);
Var i: entero; ¿cuántos recursos de
Inicio tiempo y memoria
i:= 0; consume este algoritmo?
a[n]:= x;
repetir ¿qué hace este
i:= i + 1; algoritmo?
hasta a[i] = x;
Devolver (i);
Fin
Algoritmia Elemental
❑ Factores de los que dependen los recursos necesarios:
⚫ Internos:
✓ Tamaño de la entrada.
✓ Naturaleza de los datos de entrada.
⚫ Externos:
✓ Tipo de ordenador.
✓ Lenguaje de programación.
✓ Implementación
¿g ∈ 𝑂 𝑓 ?
Notación Asintótica
❑ Ejemplo. Comprobar que t(n) = 3n2 + 2n –5 es de orden de O(n2).
⚫ Para ello tenemos que comprobar que 3n2 + 2n –5 c n2 .
⚫ Solución. 3n2 + 2n –5 5 n2. Entonces diremos que t(n) es de O(n2).
❑ Gráficamente.
¿t(n) ∈ 𝑂 𝑛3 ?
Notación Asintótica
❑ Propiedades de O.
æê expresión - expresión ú ö
t ( n) = t ( expresión1 ) + ( t ( expresión 2 ) + t ( expresión3 ) + t ( cuerpo)) × ççê 2 1
ú +1÷÷
èë expresión 3 û ø
t (n) = t ( procedure) + 1
𝑡 𝑛 =𝑡 𝑛−3 +1
Notación Asintótica
❑Cota Inferior. Notación .
❑ Tiene sentido en el análisis del mejor caso
❑ Es la cota que determina acotaciones inferiores lo más exactamente
posibles para valores crecientes de la entrada.
❑ Definición. Sea f: →[0,), se define el conjunto de funciones de
orden de f como:
(f) ={g: →[0,) / c, c > 0, n0, de manera que,
g(n) cf(n) n n0}
❑ Diremos que una función g: →[0,) es de orden de f si g (f).
g (f) indica que g está acotada inferiormente por algún
múltiplo de f.
Notación Asintótica
❑ Propiedades de . f ( n) = n 3 ; g ( n) = n 2 ; h( n) = n
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
6 2 8 3 5 7 9 0 1 4 6 2 8 3 5 7 9 0 1 4
6 4
¿Exáctamente? Peor caso
public class BusqSecuencial {
/**
* Búsqueda secuencial en un array de enteros
* @param a : array de elementos en el que buscar
* @param x : elemento buscado
* @return la posición del elemento en el array,
* si está, ó -1, si el elemento no está
*/
public static int busqSec(int[] a,int x){
int i = 0;
while (i<[Link] && a[i]!=x){
i++;
}
if (i<[Link]) return i;
else return -1;
}}
𝑇 𝑛 = 1 + 5 + 2 𝑛 + 1 = 7𝑛 + 2
Análisis de algoritmos no recursivos:
Ordenación por inserción
0 1 2 3 4 5 6
/** 6 2 8 3 5 7 9
*
* @param a array de enteros a
* ordenar por insercion 0 1 2 3 4 5 6
*/ 2 6 8 3 5 7 9
public static void insercion(int[] a){
for (int i = 1; i<[Link]; i++){ 0 1 2 3 4 5 6
// a[0..i-1] está ordenado
int j = i-1; 2 6 8 3 5 7 9
int x = a[i];
// insertamos a[i] en a[0..i-1] 0 1 2 3 4 5 6
// para que a[0..i] quede ordenado
2 3 6 8 5 7 9
while (j>=0 && a[j]>x) {
a[j+1]= a[j];
j--; 0 1 2 3 4 5 6
}
2 3 5 6 8 7 9
a[j+1]=x;
}
} 0 1 2 3 4 5 6
2 3 5 6 7 8 9
0 1 2 3 4 5 6
2 3 5 6 7 8 9
Análisis de algoritmos no recursivos:
Ordenación por inserción
❑ Tamaño de la entrada: longitud del array a ordenar n.
❑ Caso mejor: el array está ordenado
⚫ El cuerpo del bucle anidado no se ejecuta nunca
/**
*
* @param a array de enteros a
* ordenar por insercion
*/
public static void insercion(int[] a){
for (int i = 1; i<[Link]; i++){
// a[0..i-1] está ordenado
int j = i-1;
0 1 2 3 4 5 6
int x = a[i];
// insertamos a[i] en a[0..i-1] 2 3 5 6 7 8 9
// para que a[0..i] quede ordenado
while (j>=0 && a[j]>x) {
a[j+1]= a[j];
j--;
}
a[j+1]=x;
}
}
t (n ) (n )
Análisis de algoritmos no recursivos:
Ordenación por inserción
❑ Caso peor: el array está
ordenado de forma decreciente
⚫ El cuerpo del bucle anidado se
ejecuta siempre
0 1 2 3 4 5 6
/** 9 8 7 5 3 2 0
*
* @param a array de enteros a
* ordenar por insercion
*/
public static void insercion(int[] a){
for (int i = 1; i<[Link]; i++){
// a[0..i-1] está ordenado
int j = i-1;
int x = a[i];
// insertamos a[i] en a[0..i-1]
// para que a[0..i] quede ordenado
while (j>=0 && a[j]>x) {
a[j+1]= a[j];
j--;
}
}
}
a[j+1]=x;
( )
t (n ) n 2
Ordenación por inserción, peor caso. ¿Exactamente?
/** 𝑛−1 𝑖−1
*
* @param a array de enteros a 𝑇 𝑛 = 1 + (2 + 2 + 2 + 2 + 4 + 4 + 2 + 3) =
* ordenar por insercion 𝑖=1 𝑗=0
*/ 𝑛−1 𝑖−1
public static void insercion(int[] a){
for (int i = 1; i<[Link]; i++){ 1 + 11 + 10 =
// a[0..i-1] está ordenado 𝑖=1 𝑗=0
int j = i-1; 𝑛−1 𝑛−1
int x = a[i];
// insertamos a[i] en a[0..i-1] 1 + 11 + 10i = 1+ 11(n-1)+10 𝑖 =
// para que a[0..i] quede ordenado 𝑖=1 𝑖=1
while (j>=0 && a[j]>x) { 𝑛−2 𝑛
a[j+1]= a[j]; 11𝑛 − 10 + 10 = 5𝑛2 + 𝑛 − 10
j--; 2
}
a[j+1]=x;
}
}
Análisis de algoritmos no recursivos:
Ordenación por selección
0 1 2 3 4 5 6
/** 6 2 8 3 5 9 7
* @param a array de enteros
* a ordenar por selección
*/ 0 1 2 3 4 5 6
public static void seleccion(int[] a){ 2 6 8 3 5 9 7
for (int i = 0; i<[Link]-1; i++){
// a[0..i-1] está ordenado
int min = i; 0 1 2 3 4 5 6
for (int j=i+1;j<[Link];j++) { 2 3 8 6 5 9 7
// min es el menor elemento
// del array a[i..j-1]
if (a[j]< a[min]) min = j; 0 1 2 3 4 5 6
} 2 3 5 6 8 9 7
//intercambiamos a[i] y a[min]
int temp = a[i];
a[i] = a[min]; 0 1 2 3 4 5 6
a[min] = temp; 2 3 5 6 8 9 7
}
}
0 1 2 3 4 5 6
2 3 5 6 7 9 8
0 1 2 3 4 5 6
2 3 5 6 7 8 9
Análisis de algoritmos no recursivos:
Ordenación por selección
/**
* @param a array de enteros
* a ordenar por selección
*/
public static void seleccion(int[] a){
for (int i = 0; i<[Link]-1; i++){
// a[0..i-1] está ordenado
int min = i; ¿Orden?
for (int j=i+1;j<[Link];j++) {
// min es el menor elemento
// del array a[i..j-1]
t(n) ÎQ(n ) 2
y++;
}
¿Orden? }
}
}
Mejor, peor caso? Caso medio?
public static void muyImpar (int n) {
❑ Los distintos casos se int x = 0, y = 0;
estudian con respecto a la int i=n, j, k;
NATURALEZA, NO con if (( i % 2 ) == 0 ) {
respecto al tamaño. for ( j = 1; j <= n; j++ ) {
❑ Es decir, con respecto a n x++;
❑ O por la lógica del }
algoritmo for ( k = 1; k <= i; k++ ) {
y++;
}
}
}
Ejemplo
/**
* @param n número natural
* @return n! = 1*...*n
*/
public static int factorial(int n){
if (n<0) throw
new IllegalArgumentException(“número no válido");
if (n == 0) return 1;
else return n*factorial(n-1);
}
Ecuaciones de Recurrencia
Ecuaciones de Recurrencia
❑ A menudo es la etapa final en el análisis de algoritmos
(recursivos).
❑ Es normal que un procedimiento se base en
procedimientos auxiliares, haga llamadas recursivas para
tamaños menores o reduzcan el tamaño del problema
progresivamente.
❑ El tiempo t(n) del algoritmo original se expresa en función
del tiempo para el mismo algoritmo pero para problemas
de menor tamaño con lo que obtenemos una ecuación en
recurrencia.
⚫ Ejm para el alg factorial: t(n)=t(n-1)+5
Tipos de ecuaciones de recurrencias
x n−k
(a x
o
k
+ a1 x k −1
)
+ ... + a k = 0
❑ La ecuación característica tiene la forma:
ao x k + a1 x k −1 + ... + a k = 0
Raíces Reales Distintas
❑ Solución.
k
t (n ) = ci ri n donde ri son las distintas
raíces (soluciones) a la
i =1
ecuación característica
t n = t n−1 + t n−2 , n 2
t 0 = 0, t1 = 1
Solución al Ejercicio
❑ Solución: tn = c1r1n
+ n
c 2 r2 .
c1 + c 2 = 0 1 1
❑ Constantes: c1 = − , c2 = .
c r +
11 2 2c r = 1 5 5
Solución al Ejercicio
/** /**
* @param n número natural * @param n número natural
* @return el n-ésimo elemento de fibonacci * @return el n-ésimo elemento de fibonacci
* Implementación ineficiente * Implementación eficiente
*/ */
public static int fibonacci(int n){ public static int fibonacciNoRec(int n){
//n >=0 if (n==0) return 0;
if (n==0) return 0; else {
if (n==1) return 1; int fibAnt = 0;
else return fibonacci(n-1)+fibonacci(n-2); int fibAct = 1;
} for (int i = 1; i<n; i++){
int fibInt = fibAnt;
fibAnt = fibAct;
fibAct = fibInt + fibAnt;
}
5 return fibAct;
4 3 }
}
3 2 2 1
2 1 1 0 1 0
t 0 = 0
t n = 5t n−1 − 8t n−2 + 4t n−3 , t1 = 1
t = 2
2
Solución al Ejercicio
❑ Ecuación característica:
ì x1 =1 con multiplicidad 1
x - 5x + 8x - 4 = 0 Þ ( x -1) ( x - 2) = 0 Þ í
3 2 2
î x2 = 2 con multiplicidad 2
❑ Solución:
t n = C1 (1) + C 2 (2 ) + C3 n(2 ) .
n n n
❑ Constantes:
C1 + C2 = 0,
1
C1 + 2C2 + 2C3 = 1, C1 = −2, C2 = 2, C3 = −
C + 4C + 8C = 2, 2
1 2 3
n +1 n −1
❑ Solución final: tn = 2 − n2 −2
Ecuaciones no Homogéneas (método 1)
❑ Vamos a suponer la siguiente ecuación:
t (n) − 2t (n − 1) = 3 n
k s
❑ Ecuación Característica:
k s
d i +1
ai x (x − bi ) = 0 con d i el grado del polinomio p i (n)
k −i
i =0 i =1
Y a continuación se procede de la misma forma que con las ecuaciones homogéneas
Ecuaciones no Homogéneas
❑ Ejemplo:
𝑡(𝑛) = 2𝑡(𝑛 − 1) + 𝑛 + 2𝑛 ;
𝑡 𝑛 − 2𝑡 𝑛 − 1 = 𝑏1𝑛 𝑝1 𝑛 + 𝑏1𝑛 𝑝2 𝑛 ;
𝑡 𝑛 − 2𝑡 𝑛 − 1 = 1𝑛 𝑛 + 2𝑛 1;
Ec. caract → (x − 2) 𝑥 − 1 2
𝑥−2 =0
t (n) = C1 2 + C2 n2 + C3 + C4 n
n n
❑ Si expandimos entonces:
n −1
t (n) = 5 + t (n − 1) = 5 + 5 + t (n − 2) = ... = 5 + t (1) = 5n − 4
i =1
Análisis de Algoritmos Recursivos
Las torres de Hanoi
/**
*
* @param n numero de discos
* @param a varilla origen
* @param b varilla intermedia
* @param c varilla destino
*/
A B C }
0 n=0
t (n ) =
2t (n − 1) + 1 en otro caso
❑ Si expandimos entonces:
n −1 n −1
t (n ) = 2t (n − 1) + 1 = 2 t (n − 2 ) + 2 + 1 = ... ... = 2 t (n − n ) + 2 = 2i 2n
2 n n i
i =0 i =0
Tipos de ecuaciones de recurrencias
❑ Lineales
1. Homogéneas
2. No-homogéneas
❑ No lineales
⚫ Cambio de variable. n = 3k ( ) ( )
t 3k = 4t 3k −1 + 9k
⚫ Ecuación conocida. t k = 4t k −1 + 9 k
𝑡𝑘 = 𝑐1 4𝑘 𝑐2 9𝑘
⚫ Deshacemos el cambio de variable:
t (n ) = nt (n 2), t (1) =
2 1
3
❑ Solución. En este caso se toman logaritmos:
2
⚫ Primero un cambio de variable. 𝑡𝑘 = 2𝑘 𝑡𝑘−1
⚫ Cambio de Rango. Tomamos logaritmos en ambos lados y renombramos:
𝑣𝑘 = log 2 𝑡𝑘
⚫ Ecuación conocida.
𝑣𝑘 = 𝑘 + 2𝑣𝑘−1
𝐸𝑐 → 𝑥 − 2 𝑥 − 1 2 =0
Cambio de Rango
t (n ) = nt (n 2), t (1) =
2 1
𝑣𝑘 = 𝑐1 2𝑘 + 𝑐2 +𝑐3 𝑘 De aquí extraemos que:
3
𝑐1 2𝑘 +𝑐2 +𝑐3 𝑘
𝑡𝑘 = 2 t 2 = 2𝑡 2 1 =
2
9
1
= 2𝑐1 +𝑐2
3
2/9 = 22𝑐1+𝑐2+𝑐3
16/81 = 24𝑐1+𝑐2+2𝑐3
/**
* @param l lista de números a sumar
* @param min y max, índices máximo y mínimo a suma
* @return Suma de los elementos de la lista
* Implmentación recursiva
*/
public static int suma(List<Integer> l,int min,int max){
if (max < min) return 0;
if (max == min) return [Link](min);
else {
int s1 = suma(l, min,(min+max)/2);
int s2 = suma(l, (min+max)/2+1,max);
return s1+s2;
}
}
Análisis de algoritmos recursivos
Búsqueda binaria
izda medio dcha
/**
* @param a array en el que se busca x = 4
* suponemos que está ordenado
0 1 2 3 4 5 6 7
* @param x elemento buscado
* @return posición en la que aparece x, si 2 3 5 6 7 8 8 9
* está, o -1, si no está izda medio dcha
*/
public static int busqBinaria(int[] a,int x){ 0 1 2 3 4 5 6 7
int izda = 0,dcha = [Link]-1; 2 3 5 6 7 8 8 9
int medio = (izda + dcha)/2;
while (izda <= dcha && a[medio]!=x){
if (a[medio]>x) dcha = medio - 1;
izda medio
dcha
else izda = medio + 1;
0 1 2 3 4 5 6 7
medio = (izda + dcha)/2;
} 2 3 5 6 7 8 8 9
if (izda <= dcha) return medio;
else return -1;
}
❑ Límites:
⚫ Definición. Se dice que la función f(n) tiende al límite a cuando n
tiende a infinito, si para todo número real positivo δ,
independientemente de lo pequeño que sea, f(n) dista de a en
una cantidad menor que δ para todos los valores de n
suficientemente grandes.
❑ Límites:
⚫ Proposición. Cuando f(n) no tiende a un límite, ni tampoco a +
o -, diremos que f(n) oscila cuando n tiende a infinito. Si es
posible encontrar una constante k tal que –k < f(n) < k para
todos los valores de n, diremos que f(n) oscila de forma finita, en
caso contrario, f(n) oscila de forma infinita. P.e. (-1)n y (-1)n n.
❑ Límites:
⚫ Proposición. Si dos funciones f(n) y g(n) tienden respectivamente
a los límites a y b cuando n tiende a infinito, entonces f(n) g(n)
tiende al límite a b.
❑ Series:
⚫ Proposición. (Serie aritmética) Sea Sn la suma de los n primeros términos
de la serie aritmética a, a + d, a + 2d, … . Entonces:
n (n − 1) d
Sn = a n +
2
⚫ Proposición. (Serie geométrica) Sea Sn la suma de los n primeros
términos de la serie geométrica a, ar, ar2, … (caso especial: Si r = 1,
( )
entonces Sn = an). Entonces:
a 1− r n
Sn =
(1 − r )
Nociones Básicas de Matemáticas
❑ Series:
⚫ Proposición. Para cualquier entero k 0 tenemos que:
n
n (n + 1)(n + k + 1)
(i (i + 1)(i + k )) =
i =1 k +2
n
n (n + 1)
⚫
i =1
i=
2
Nociones Básicas de Matemáticas
❑ Series:
⚫ Proposición.
n
n (n + 1) (2n + 1)
i =1
i = 2
6
⚫ Sea r cualquier entero positivo. Entonces
n r +1
n
i=1
i r
=
( r + 1)
+ pr ( n)