Você está na página 1de 8

Lista 1

Endrew Rafael Treptow Hang


Questão 1)

Código implementado:
import time

def fibonacci_recursive(n):
if n <= 1:
return n
return fibonacci_recursive(n-1) + fibonacci_recursive(n-2)

def fibonacci(n):
count = 1
n1, n2 = 0, 1
nth = 0

while count < n:


nth = n1 + n2
n1 = n2
n2 = nth
count += 1
return nth

if __name__ == "__main__":
for i in range(1, 31):
start = time.time()
fibonacci_recursive(i)
end = time.time()
print(end-start)
for i in range(1,31):
start = time.time()
fibonacci(i)
end = time.time()
print(end-start)

Gráfico obtido:
Questão 2)

Análise do código:

unsigned int potencia(unsigned int b, unsigned int e)


{
unsigned int r; // O(1)
if (e == 0) // O(1)
return 1; // O(1)
r = potencia(b, e / 2);
if (e % 2 == 0) // O(1)
return r * r; // O(1)
else
return r * r * b; // O(1)
}

Melhor caso: O(1) quando a variável e é igual a 0

Pior caso: Chamadas recursivas para a função potência, então T(n) = T(n/2) + 5

T(n) = T(n/2) + 5

utilizando séries:
𝑛
𝑇(𝑛) = 𝑇 ( ) + 5
2
𝑛 𝑛
𝑇 ( ) = 𝑇 ( 2) + 5
2 2
𝑛 𝑛
𝑇 ( ) = 𝑇 ( 3) + 5
3 2
...
𝑛 𝑛
𝑇 ( 𝑙−1 ) = 𝑇 ( 𝑙 ) + 5
2 2

𝑛
=1
2𝑙
𝑛 = 2𝑙
𝑙 = log 2 𝑛

portanto a recorrência resulta em T(n) = (T(1)+5) * log n = 6*log n

Complexidade de tempo: O (log n)

Complexidade de espaço: No pior caso o tamanho da pilha é log n, portanto a complexidade


de espaço do algoritmo é O (log n)
Questão 3a)
𝑛
𝑇(𝑛) = 𝑇 ( ) + 𝑛
2
𝑇(1) = 1
𝑛 𝑛
𝑇(𝑛) = 𝑇 ( 1 ) + 0
2 2
𝑛 𝑛 𝑛
𝑇 ( 1) = 𝑇 ( 2) + 1
2 2 2
𝑛 𝑛 𝑛
𝑇 ( 2) = 𝑇 ( 3) + 2
2 2 2

𝑛 𝑛
𝑇(𝑛) = 𝑇 ( 𝑙 ) + 𝑙−1
2 2
𝑛
𝑇(𝑛) = 𝑇(1) + 𝑙−1
2
log2 𝑛
𝑛
𝑇(𝑛) = 𝑇(1) + ∑
2𝑖
𝑖=0

log2 𝑛
1
𝑇(𝑛) = 𝑇(1) + 𝑛 ∗ ∑
2𝑖
𝑖=0

log2 𝑛
1𝑖
𝑇(𝑛) = 𝑇(1) + 𝑛 ∗ ∑
2
𝑖=0

Resultado: n está dominando assintoticamente o somatório, portanto T(n) = O(n)

Questão 3b)

𝑇(𝑛) = 2𝑇(𝑛 − 1) + 𝑛
2𝑇(𝑛 − 1) = 22 𝑇(𝑛 − 2) + 2(𝑛 − 1)

22 𝑇(𝑛 − 2) = 23 𝑇(𝑛 − 3) + 22 (𝑛 − 2)

𝑇(𝑛) = 2𝑙 𝑇(𝑛 − 𝑙) + 2𝑙−1 𝑇(𝑛 − 𝑙 − 1) + ⋯ + 2(𝑛 − 1) + 𝑛


𝑛 − 𝑙 = 1 => 𝑙 = 𝑛 − 1

𝑇(𝑛) = ∑ 2𝑙 (𝑛 − 1)
𝑖=0

𝑇(𝑛) = ∑ 2𝑖 𝑛 + ∑ 𝑖 ∗ 2𝑖
𝑖=0 𝑖=0
𝑇(𝑛) = 𝑛 ∗ ∑ 2𝑖 + ∑ 𝑖 ∗ 2𝑖
𝑖=0 𝑖=0

∑ 2𝑖 = 20 + 21 + ⋯ + 2𝑛 + 2𝑛+1
𝑖=0
𝑛
𝑖 𝑛+1
∑2 + 2 = 2 + ∑ 2𝑖+1
0

𝑖=0 𝑖=0
𝑛
𝑖 𝑛+1
∑2 + 2 = 2 + 2 ∑ 2𝑖
0

𝑖=0 𝑖=0
𝑛

∑ 2𝑖 = 2𝑛+1 − 1
𝑖=0

𝑇(𝑛) = 𝑛 ∗ ∑ 2𝑖 − ∑ 𝑖 ∗ 2𝑖
𝑖=0 𝑖=0

𝑇(𝑛) = 𝑛 ∗ (2𝑛+1 − 1) − ∑ 𝑖 ∗ 2𝑖
𝑖=0

∑ 𝑖 ∗ 2𝑖 = 0 ∗ 20 + 1 ∗ 21 + 2 ∗ 22 + ⋯ + 𝑛 ∗ 2𝑛 + (𝑛 − 1) ∗ 2𝑛−1
𝑖=0

∑ 𝑖 ∗ 2𝑖 + (𝑛 + 1) ∗ 2𝑛 + 1 = 0 ∗ 20 + ∑(𝑖 + 1) ∗ 2𝑖+1
𝑖=0 𝑖=0

∑ 𝑖 ∗ 2𝑖 + 𝑛 ∗ 2𝑛+1 + 2𝑛+1 = 2 ∗ ∑ 𝑖 ∗ 2𝑖 + 2 ∗ ∑ 2𝑖
𝑖=0 𝑖=0 𝑖=0

∑ 𝑖 ∗ 2𝑖 + 𝑛 ∗ 2𝑛+1 + 2𝑛+1 = 2 ∗ ∑ 𝑖 ∗ 2𝑖 + 2 ∗ (2𝑛+1 − 1)


𝑖=0 𝑖=0

𝑛 ∗ 2𝑛+1 + 2𝑛+1 = ∑ 𝑖 ∗ 2𝑖 + 2 ∗ (2𝑛+1 − 1)


𝑖=0

∑ 𝑖 ∗ 2𝑖 = 𝑛 ∗ 2𝑛+1 − 2𝑛+1 + 2
𝑖=0

𝑇(𝑛) = 𝑛 ∗ (2𝑛+1 − 1) − (𝑛 ∗ 2𝑛+1 − 2𝑛+1 + 2)

𝑇(𝑛) = 𝑛 ∗ 2𝑛+1 − 𝑛 − 𝑛 ∗ 2𝑛+1 + 2𝑛+1 − 2

𝑇(𝑛) = 2𝑛+1 − 𝑛 − 2

Resultado: 2𝑛+1 está dominando assintoticamente os outros, portanto T(n) = O(2𝑛 )

Questão 3c)
𝑛
𝑇(𝑛) = 4𝑇 ( ) + 𝑛
2
𝑛 𝑛 𝑛
4𝑇 ( 1 ) = 42 𝑇 ( 1 ) + 4 ∗ ( 1 )
2 2 2
𝑛 𝑛 𝑛
42 𝑇 ( 2 ) = 43 𝑇 ( 2 ) + 42 ∗ ( 2 )
2 2 2

𝑛 𝑛 𝑛
𝑇(𝑛) = 𝑛 + 41 𝑇 ( 1 ) + 42 𝑇 ( 2 ) + ⋯ + 4𝑙 𝑇( 𝑙 )
2 2 2
𝑛−1
𝑛
𝑇(𝑛) = ∑ 4𝑖 ( 𝑖 )
2
𝑖=0
𝑛−1

𝑇(𝑛) = ∑ 2𝑖 𝑛
𝑖=0
𝑛−1

𝑇(𝑛) = 𝑛 ∗ ∑ 2𝑖
𝑖=0

𝑇(𝑛) = 𝑛 ∗ (2𝑙+1 − 1)

𝑇(𝑛) = 𝑛 ∗ (2 ∗ 2𝑙 − 1)

𝑇(𝑛) = 𝑛 ∗ (2 ∗ 𝑛 − 1)

𝑇(𝑛) = 2𝑛2 − 𝑛
Resultado: 𝑛2 está dominando assintoticamente os outros, portanto T(n) = O(𝑛2 )

Questão 3d)
𝑛
𝑇(𝑛) = 𝑇 ( 1 ) + log 2 𝑛
2
𝑛 𝑛 𝑛
𝑇 ( 1 ) = 𝑇 ( 2 ) + log 2 ( 1 )
2 2 2
𝑛 𝑛 𝑛
𝑇 ( 2 ) = 𝑇 ( 3 ) + log 2 ( 2 )
2 2 2

𝑛 𝑛
𝑇(𝑛) = 𝑇 ( 𝑙 ) + log 2 ( 𝑙−1 )
2 2
𝑛
𝑇(𝑛) = 𝑇(1) + log 2 ( 𝑙−1 )
2
𝑛
𝑙 = 𝑙 => 𝑙 = log 2 𝑛
2
log2 (𝑛)−1
𝑛
𝑇(𝑛) = ∑ log 2
2𝑖
𝑖=0
log2 (𝑛)−1
log 2 𝑛
𝑇(𝑛) = ∑
log 2 2𝑖
𝑖=0

log2 (𝑛)−1
log 2 𝑛
𝑇(𝑛) = ∑
𝑖 ∗ log 2 2
𝑖=0

log2 (𝑛)−1
log 2 𝑛
𝑇(𝑛) = ∑
𝑖
𝑖=0

log2 (𝑛)−1
1
𝑇(𝑛) = log 2 𝑛 ∗ ∑
𝑖
𝑖=0

Resultado: log 2 𝑛 está dominando assintoticamente os outros, portanto T(n) = O(log n)

Questão 5)

Inserir inicio:

void insertInit(struct Lista *list, int elem){


struct Lista *new;
new = malloc(sizeof(Lista));
new->elem = elem;
new->ptr = list;
list = new;
}

Inserir final:

void insertEnd(struct Lista *list, int elem){


struct Lista *aux = lista->ptr;
while (aux->ptr != NULL)
{
aux=aux -> ptr
}
aux->elem = elem
}

A função inserir início não possui nenhum looping nem algo que possa causar uma demora
extra na função, portanto sua velocidade é constante;

Porém a função inserir final possui um loop que passa por todas as posições da lista, como a
lista possui n elementos, a função insert end é O(n)
Questão 6)

void imprimir(struct Arvore *r)


{
if (r != NULL)
{
imprimir (r->esq); // T(n/2)
printf("%d ", r->elem); // O(1)
imprimir (r->dir); // T(n/2)
}
}

Como é uma arvore balanceada, cada um dos nodos à esquerda e à direita devem ter metade
do seu parente, portanto para cada um deles T(n) = T(n/2), o resto da função é executado em
O(1) portanto, para a função imprimir T(n) = 2T(n/2) + O(1), utilizando séries:
𝑛
𝑇(𝑛) = 2𝑇 ( ) + 1
2
𝑛 𝑛
2𝑇 ( ) = 22 𝑇 ( 2 ) + 1
2 2
𝑛 𝑛
22 𝑇 ( 2 ) = 23 𝑇 ( 3 ) + 1
2 2

𝑛 𝑛
2𝑙−1 𝑇 ( 𝑙−1 ) = 2𝑙 𝑇 ( 𝑙 ) + 1
2 2

𝑛
=1
2𝑙
𝑛 = 2𝑙
𝑙 = log 2 𝑛
n n n
T(n) + 2T ( ) + 22 T ( 2 ) + ⋯ + 2l−1 T ( l−1 )
2 2 2
n n n n
= 2T ( ) + 2 T ( 2 ) + 23 T ( 3 ) + ⋯ + 2l T ( l )
2
2 2 2 2
𝑛
𝑇(𝑛) = 1 + 1 + 1 + ⋯ + 1 + 2𝑙 𝑇 ( 𝑙 )
2
𝑇(𝑛) = log 2 𝑛 + 𝑛
Como n domina assintoticamente log n, então a complexidade de tempo é O (n)

A complexidade de espaço será a maior altura na pilha, para uma árvore balanceada, esta
altura será de log n, portanto a complexidade de espaço é O (log n)

Você também pode gostar