Auxiliar CC30A
Abril 06, 2001
Recurrencias y Ordenes de Tiempo

Auxs: Bárbara Poblete, Rhodrigo Meza, Rodrigo Paredes.




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:

Con esta información:

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:

Con esta información:

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))