MAC5711 ANÁLISE DE ALGORITMOS: LISTA 1
Entregar: Exercícios 1.2 (apenas itens (a) e (b)), 1.3 (apenas item (e)), 2.4 e 3.7.
Prazo: 16/maio/2021 às 23h59
Instruções: ATENÇÃO às instruções postadas no e-disciplinas para o formato de entrega.
Os sobrescritos ao lado de cada rótulo de exercício indicam aproximadamente a partir de qual aula
é recomendável que se trabalhe naquele exercício.
1. Notação assintótica e Recorrências
Exercício 1.1.A01 Lembre-se que lg n denota o logaritmo na base 2 de n. Usando a definição de
notação O, prove que
(a) 3n não é O(2n );
(b) log10 n é O(lg n);
(c) lg n é O(log10 n).
Exercício 1.2.A01 Usando a definição de notação O, prove que
(a) n7 − 7n5 + 10π/e n2 + 5000 = O(n7 );
(b) 2dn/5e = O(n);
(c) n = O(2n );
(d) n/1000 não é O(1);
(e) n2 /2 não é O(n).
Exercício 1.3.A02 Prove ou dê um contraexemplo para cada uma das afirmações abaixo:
√
(a) lg n = O(lg n).
(b) Se f (n) = O(g(n)) e g(n) = O(h(n)) então f (n) = O(h(n)).
(c) Se f (n) = O(g(n)) e g(n) = Θ(h(n)) então f (n) = Θ(h(n)).
(d) Suponha que lg(g(n)) > 0 e que f (n) ≥ 1 para todo n suficientemente grande. Nesse caso,
se f (n) = O(g(n)) então lg(f (n)) = O(lg(g(n))).
(e) Se f (n) = O(g(n)) então 2f (n) = O(2g(n) ).
Pn k Pn
Exercício 1.4.A07 Prove que: (a) j=1 j ∈ Θ(nk+1 ); (b) j=1
j/2j ≤ 2.
Exercício 1.5.A04 Seja C uma constante real positiva. Para cada uma das recorrências T (n) abaixo,
encontre uma fórmula fechada (não recursiva) — mesmo que não seja válida para todos valores de n
— e deduza um limitante em notação O(·) para a função T . Depois disso, prove que, pelo menos nos
valores de n que você escolheu, T (n) é igual à fórmula que você encontrou. Considere que T (0) = 1.
(a) T (n) = 2T (bn/2c) + Cn2 ;
(b) T (n) = 8T (bn/2c) + Cn2 ;
Data: 26 de março de 2021 às 20h34 -0300.
1
2 MAC5711 ANÁLISE DE ALGORITMOS: LISTA 1
(c) T (n) = 2T (bn/2c) + Cn3 ;
(d) T (n) = T (b9n/10c) + Cn.
Exercício 1.6.A04 Seja M (n) definida pela recorrência
1 se n = 0 ou n = 1,
M (n) :=
M (k) + M (n − 1 − k) + n se n ≥ 2.
min
0≤k≤n−1
Mostre que M (n) ≥ n log10 n para todo n ≥ 1.
2. Ordenação e Seleção por Comparação
Exercício 2.1. A03 Escreva um algoritmo que ordena uma lista de n itens dividindo-a em três
sublistas de aproximadamente n/3 itens, ordenando cada sublista recursivamente e intercalando as
três sublistas ordenadas. Analise seu algoritmo concluindo qual é o seu consumo de tempo.
Exercício 2.2.A03 Seja A[1 . . n] um vetor de inteiros e i e j dois índices distintos de A, ou seja, i
e j são inteiros entre 1 e n. Dizemos que o par (i, j) é uma inversão de A se i < j e A[i] > A[j].
Escreva um algoritmo O(n lg n) que devolva o número de inversões em um vetor A, onde n é o
número de elementos em A. Você pode assumir que não existem itens repetidos no vetor.
Exercício 2.3. A07 Descreva um algoritmo que, dados inteiros n e k, juntamente com k listas
ordenadas que em conjunto tenham n registros, produza uma única lista ordenada contendo todos
os registros dessas listas (isto é, faça uma intercalação). O seu algoritmo deve ter complexidade
O(n lg k). Note que isto se transforma em O(n lg n) no caso de n listas de 1 elemento, e em O(n) se
só houver duas listas (no total com n elementos).
Exercício 2.4.A03 Considere a sequência de vetores Ak [1 . . 2k ], Ak−1 [1 . . 2k−1 ], . . . , A1 [1 . . 21 ], e
A0 [1 . . 20 ]. Suponha que cada um dos vetores é crescente. Queremos reunir, por meio de sucessivas
operações de intercalação (= merge), o conteúdo dos vetores A0 , . . . , Ak em um único vetor crescente
B[1 . . n], onde n = 2k+1 − 1. Escreva um algoritmo que faça isso em O(n) unidades de tempo. Use
como subrotina o Intercala visto em aula.
Exercício 2.5. A07 Suponha que A[1 . . m] é um heap. Suponha que i < j e A[i] < A[j]. Se os
valores de A[i] e A[j] forem trocados, A[1 . . m] continuará sendo um heap? Repita o exercício sob a
hipótese A[i] > A[j].
Exercício 2.6 (CLRS 6.5-3).A07 Escreva em pseudocódigo cada um dos seguintes procedimentos,
que implementam uma fila de prioridade com um heap de mínimo: Heap-Mínimo, Heap-Extrai-
Mínimo, Heap-Diminui-Chave e Heap-Insere.
Exercício 2.7.A06 Sejam X[1 . . n] e Y [1 . . n] dois vetores, cada um contendo n números ordenados.
Escreva um algoritmo O(lg n) para encontrar uma das medianas de todos os 2n elementos nos
vetores X e Y .
Exercício 2.8.A06 Para esta questão, vamos dizer que a mediana de um vetor A[p . . r] com números
inteiros é o valor que ficaria na posição A[b(p + r)/2c] depois que o vetor A[p . . r] fosse ordenado.
Dado um algoritmo linear “caixa-preta” que devolve a mediana de um vetor, descreva um algoritmo
simples, linear, que, dado um vetor A[p . . r] de inteiros distintos e um inteiro k, devolve o k-ésimo
mínimo do vetor. (O k-ésimo mínimo de um vetor de inteiros distintos é o elemento que estaria na
k-ésima posição do vetor se ele fosse ordenado.)
MAC5711 ANÁLISE DE ALGORITMOS: LISTA 1 3
3. Ordenação em tempo linear
Exercício 3.1.A08 Desenhe a árvore de decisão para o SelectionSort aplicado a A[1 . . 3] com
todos os elementos distintos.
Exercício 3.2 (CLRS 8.1-1).A08 Qual a menor profundidade (= menor nível) que uma folha pode
ter em uma árvore de decisão que descreve um algoritmo de ordenação baseado em comparações?
Exercício 3.3 (CLRS 8.2-1).A08 Simule a execução do CountingSort usando como entrada o
vetor
A[1 . . 11] = h6, 0, 2, 0, 1, 3, 4, 6, 1, 3, 2i.
Exercício 3.4.A08 Escreva uma função que recebe um vetor com n letras A’s e B’s e, por meio de
trocas, move todos os A’s para o início do vetor. Sua função deve consumir tempo O(n).
Exercício 3.5 (CLRS 8.2-2).A08 Mostre que o CountingSort é estável.
Exercício 3.6 (CLRS 8.2-3).A08 Suponha que o para da linha 7 do CountingSort é substituído
por
para j ← 1 até n faça
Mostre que o CountingSort ainda funciona. O algoritmo resultante continua estável?
Exercício 3.7 (CLRS 8.2-4).A08 Descreva um algoritmo que, dados n inteiros no intervalo de 1 a k,
preprocesse sua entrada e então responda em O(1) qualquer consulta sobre quantos dos n inteiros
dados caem em um intervalo [a . . b]. O preprocessamento efetuado pelo seu algoritmo deve consumir
tempo O(n + k).
Exercício 3.8 (CLRS 8.3-2).A08 Quais dos seguintes algoritmos de ordenação são estáveis: inserti-
onsort, mergesort, heapsort e quicksort. Descreva uma maneira simples de deixar qualquer algoritmo
de ordenação estável. Quanto tempo e/ou espaço adicional a sua estratégia usa?
Exercício 3.9.A01 Qual a diferença de consumo de tempo entre uma busca binária em um vetor
com n elementos e uma busca binária em um vetor com n2 elementos?
Exercício 3.10 (CLRS 8.3-4).A08 Mostre como ordenar n inteiros no intervalo de 0 até n2 − 1 em
tempo O(n).
Exercício 3.11 (CLRS 8.4-1).A08 Simule a execução do BucketSort com o vetor
A[1 . . 10] = h0.79, 0.13, 0.16, 0.64, 0.39, 0.20, 0.89, 0.53, 0.71, 0.42i.
Exercício 3.12 (CLRS 8.4-2). A08 Explique por que o consumo de tempo de pior caso para o
BucketSort é Θ(n2 ). Que simples ajuste do algoritmo melhora o seu pior caso para O(n lg n) e
mantém o seu consumo esperado de tempo linear.
Exercício 3.13 (CLRS 8.4-3).A05 Seja X uma variável aleatória que é igual ao número de caras
em duas jogadas de uma moeda justa. Quanto vale E[X 2 ]? Quanto vale E[X]2 ?
Apêndice A. Exemplos de soluções
Seguem alguns exercícios resolvidos, para que você tenha uma ideia do nível de detalhe/formalismo
adequado para suas soluções.
Note, em particular, que toda expressão/fórmula matemática aparece dentro de uma
frase com sujeito e predicado. Note ainda que expressões matemáticas aparecem sempre ligadas
por conectivos lógicos, e nunca “soltas” no meio do texto (fora de frases ou sem conectivos lógicos).
4 MAC5711 ANÁLISE DE ALGORITMOS: LISTA 1
Solução 1 (Exercício 1.2, item (e)). Suponha que n2 /2 é O(n) e vamos derivar uma contradição.
Por definição, existem constantes positivas c e n0 tais que,
(1) para qualquer inteiro n ≥ n0 , vale que n2 /2 ≤ cn.
Defina1
m0 := max{n0 , 1} e d := max{c, 1},
e
de modo que valem
(2) m0 ≥ n0 ,
(3) m0 ≥ 1,
(4) d ≥ c,
e
(5) d ≥ 1.
Defina
(6) n := 4dm0 .
Temos
(6) (5) (2)
n = 4dm0 ≥ m0 ≥ n0 .
Logo, por (1), vale que
(6) (1) (4) (6)
(7) 8d2 m20 = (4dm0 )2 /2 = n2 /2 ≤ cn ≤ dn = 4d2 m0 .
Dividindo ambas as extremidades de (7) inequação por 8d2 m0 , obtemos m0 ≤ 1/2, uma contradição,
pois m0 ≥ 1 por (3).
Concluímos que n2 /2 não é O(n).
Solução 2 (Exercício 1.3, item (b)). Vamos provar a afirmação. Suponha que f (n) é O(g(n)) e
que g(n) = O(h(n)). Da primeira suposição, obtemos que existem constantes positivas c e n0 tais
que, para todo inteiro n ≥ n0 , vale que f (n) ≤ c · g(n). Da segunda suposição, obtemos que existem
constantes positivas d e m0 tais que, para todo inteiro n ≥ m0 , vale que g(n) ≤ d · h(n).
Defina N0 := max{n0 , m0 } e C := c · d. Note que N0 e C são constantes positivas. Seja n um
inteiro tal que n ≥ N0 . Então n ≥ N0 ≥ n0 implica que f (n) ≤ c · g(n). Similarmente, n ≥ N0 ≥ m0
implica que g(n) ≤ d · h(n); multiplicando (ambos os lados d)esta última inequação por c > 0,
obtemos c · g(n) ≤ c · d · h(n) = C · h(n). Concluímos que f (n) ≤ c · g(n) ≤ C · h(n). Como n foi
escolhido arbitrariamente tal que n ≥ N0 , provamos assim que, para todo inteiro n ≥ N0 , vale que
f (n) ≤ C · h(n). Em outras palavras, provamos que f (n) é O(h(n)).
Solução 3 (Exercício 2.8). Suponha a existência de um algoritmo Mediana(A, p, r) que recebe
um vetor A[1 . . n] de inteiros e devolve a mediana de A[p . . r] em tempo O(m), onde m := r − p + 1.
O algoritmo A.1 abaixo modifica o algoritmo de seleção aleatorizado, fazendo com que o pivô da
rotina Particione sempre seja a mediana do subvetor analisado.
Note que a corretude do algoritmo A.1 segue da corretude do algoritmo aleatorizado visto na
aula 5 para seleção do k-ésimo menor elemento.
O consumo de tempo de uma chamada ao algoritmo A.1 com um vetor A[p . . r] de tamanho
n := r − p + 1 é T (n) ≤ T (n/2) + Θ(n). Aqui estamos ignorando detalhes como o piso/teto de
n/2 na potencial chamada recursiva, e levamos em conta que as chamadas às funções Mediana e
1Note a distinção entre ‘=’ e ‘:=’; o último indica que o símbolo da esquerda é definido pela expressão à direita,
como o operador de atribuição de linguagens de programação.
MAC5711 ANÁLISE DE ALGORITMOS: LISTA 1 5
Algorithm A.1 Algoritmo de seleção via medianas
1: function Seleção-por-mediana(A, p, r, k)
2: if p = r then
3: return A[p]
4: x ← Mediana(A, p, r)
5: Encontre um índice i em p . . r tal que A[i] = x
6: A[i] ↔ A[r]
7: q ← Particione(A, p, r)
8: if k = q − p + 1 then
9: return A[q]
10: if k < q − p + 1 then
11: return Seleção-por-mediana(A, p, q − 1, k)
12: else
13: return Seleção-por-mediana(A, q + 1, r, k − (q − p + 1))
Particione, bem como a busca pela mediana na linha 5, consomem tempo total Θ(n). (Como a
chamada recursiva é apenas potencial, a recorrência é descrita como ‘≤’ no lugar de ‘=’.)
Finalmente, verificamos que a recorrência T (n) ≤ T (n/2) + n, com base T (1) = 1, satisfaz
T (n) ≤ 2n sempre que n for uma potência de 2, ou seja, sempre que n = 2k para algum inteiro
k ≥ 0. Vamos provar por indução em k que T (2k ) ≤ 2k+1 . Para a base da indução, temos k = 0 e
T (20 ) = T (1) = 1 ≤ 2 = 20+1 . Seja k > 0 um inteiro. Então
T (2k ) ≤ T (2k /2) + 2k pela recorrência
k−1 k
= T (2 )+2
≤ 2(k−1)+1 + 2k pela hipótese de indução
= 2k + 2k = 2k+1 .
Isso conclui a prova de que T (n) é O(n) (provamos apenas para n potência de 2, mas isso é o
suficiente para nossos propósitos nesta disciplina).