Problema 1: Calcule el tiempo utilizado por el siguiente algoritmo:
int elevado(x,n){
/* caso base */
if (n == 0) {
return 1;
}
/* caso recursivo impar*/
else (n es impar) {
return x * elevado(x,n-1);
}
/* caso recursivo par*/
else (n es par) {
return elevado(x*x,n/2);
}
}
Solucion:
podemos ver que, si n es par:
f(n) | = 1+ f(n/2) |
si n es impar:
f(n) | = 1 + f(n-1)
= 1 + (1 + f ((n-1)/2)) = 2 + f((n-1)/2) |
debido a esto, para cualquier n tenemos la cota:
desarrollando:
si n=2^k :
hemos mostrado entonces que f(n) es de orden O(log(n))
Otro enfoque:
Un enfoque alternativo es pensar que cada vez que encontramos n par, el numero se reduce a la mitad. Expresando esto como en representación binaria, significa hacer un shift a la derecha en el número.
Por otra parte, cada vez que encontramos un n impar, el número se reduce en 1. lo que significa cambiar el ultimo digito bit de 1 a 0.
El total de operaciones por lo tanto, es el número de shifts
realizados, más el número de 1's transformados a 0's. Como
la representación binaria de n tiene log(n) digitos, tanto el número
de shifts como el total de 1 transformados en 0 están acotados por
log(n), lo que establece una cota de 2log(n) operaciones => f(n) es orden
O(log(n)).
Problema 2: Calcule el tiempo utilizado por el siguiente algoritmo:
int sumaLista (lista l){
if l.largo = 0
return 0
else l.largo = 1
return l.primerElemento
else sumaLista (l.mitadDerecha) + sumaLista
(l.mitadIzquierda);
}
Supuestos:
f(1) = 1
Caso recursivo:
f(n) = 2*f(n/2) + 2
= 2*(2*f(n/4) + 2) + 2 = 4*f(n/4) + 6
= 22*f(n/22) + 2*(22 - 1)
= 4*(2*f(n/8) + 2) + 6 = 8*f(n/8) + 14
= 23*f(n/23) + 2*(23 - 1)
= ...
f(n) = 2k*f(n/2k) + 2*(2k - 1)
suponiendo : n = 2k => k = log2n
f(n) = 2k*f(1) + 2*(2k - 1)
f(n) = n + 2*(n - 1)
f(n) = 3*n - 2 = O(n)
NOTA: este es otro ejemplo en donde la recursividad no sirve
Problema 3: Calcule el tiempo utilizado por el siguiente algoritmo
lista Msort(lista l){
if (l.length < 2)
return l;
else{
lDer= Msort(l.mitadDerecha);
lIzq= Msort(l.mitadIzquierda)
;
l= mezclaListas(lDer,
lIzq);
return l;
}
}
Supuestos:
T(1) = 1
No se considerarán las operaciones de costo unitario puesto que son de costo despreciable en la iteración (comparadas con el costo de redistribución en la lista)
Caso recursivo:
T(n) = 2*T(n/2) + n
= 2*(2*T(n/4) + n/2) + n = 4*T(n/4) +
n + n = 22*f(n/22) + 2*n
= 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8)
+ n + 2*n = 23*T(n/23) + 3*n
= ...
f(n) = 2k*T(n/2k) + k*n
suponiendo : n = 2k => k = log2n
f(n) = n*T(1) + n*log2n
f(n) = n + n*log2n = O(n*log2n)
Problema 4: Resuelva la ecuación de la forma
T(n)= p*T(n/q) + K*n
Solución: desarrollemos
T(n)= K*n + p*T(n/q)
= K*n + p(K*(n/q) + p*T(n/q2))
= K*n * (1 + (p/q)) + p2*T(n/q2)
(donde: T(n/q2)= K*(n/q2) + p*T(n/q3))
= K*n * (1+(p/q)+(p/q)2) + p3*T(n/q3)
en general:
= K*n * (1+(p/q)+(p/q)2+..+(p/q)j-1) + pj*T(n/qj)
Los otros casos:
Caso p < q :
T(n) <= K*n *(1+(p/q)+(p/q)2+..) + n^(logqn)
(donde: (1+(p/q)+(p/q)2+.. ) = 1/(1-(p/q)) )
=> = O(n)
Caso p = q :
T(n) = K*n *(1+1+1+..) + pj*T(n/qj)
^^^^^^^^
j veces
j = logqn =>
T(n) = K*n*logqn + n*T(1)
= O(n*log(n))