Playlists
Figuras: trinityscsp e Wikipedia
A análise do odômetro binário é muito parecida com o decimal.
Figura: [CLRS]
Logo para uma sequência de \(n\) (\(n \le 2^{k}\)) incrementos (com o contador a partir do \(0\)) o total de modificações é:
\[\sum_{i=0}^{\lfloor \lg n\rfloor}\left\lfloor\dfrac{n}{2^i}\right\rfloor < n\sum_{i=0}^{\infty}\frac{1}{2^i} = 2n\]
A noção da análise amortizada vem da seguinte observação:
Em outras palavras, queremos que a execução da sequência toda de \(n\) operações seja, por exemplo, \(O(n)\) mas não nos importamos se alguma das operações não for \(O(1)\).
Em outras palavras, o custo médio de cada operação e, portanto, o custo amortizado de cada operação é \(O(1)\).
Vamos apresentar uma estrutura de dados para filas e exemplificar como podemos empregar o método do banqueiro1.
A implementação funcional mais comum de filas envolve o uso de
duas listas f
e r
.
f
contém os elementos no início (front) da fila
r
contém os elementos do final (rear) da fila
-- f r
type Fila a = ([a], [a])
A cabeça da lista está localizada em f
, então tanto a função
head
quanto a função tail
operam neste ponto
head :: Fila a -> a
head (x:f, r) = x
tail :: Fila a -> Fila a
tail (x:f, r) = (f, r)
De maneira semelhante, o último elemento da fila é o primeiro
elemento de r
, logo snoc
2
simplesmente adiciona um elemento à r
.
snoc :: Fila a -> a -> Fila a
snoc (f, r) x = (f, x : r)
r
e retirados de f
.f
estiver vazio (ou seja, há elementos em
r
).f
estará vazio se e
somente se r
também estiver vazio (ou seja, a fila toda está
vazia).
f
estivesse vazio e
r
não, então o primeiro elemento da fila seria o último
elemento de r
(acesso em tempo \(O(n)\)).head
(e tail
) sempre rodam em
tempo \(O(1)\).Mantendo o invariante
Para isso precisaremos adaptar as funções que alteram a fila
(tail
e snoc
). Vamos usar uma função auxiliar que faz o trabalho:
check :: Fila a -> Fila a
check ([], r) = (rev r, [])
check q = q
snoc :: Fila a -> a -> Fila a
snoc (f, r) x = checkf (f, x : r)
tail :: Fila a -> Fila a
tail (x:f, r) = checkf (f, r)
\[\sum_{i=1}^{n} a_i \ge \sum_{i=1}^{n}t_i\]
Onde \(a_i\) é o custo amortizado da operação \(i\), \(t_i\) é o custo real da operação \(i\) e \(n\) é o número total de operações.
\[\sum_{i=1}^{j} a_i \ge \sum_{i=1}^{j}t_j\]
Onde \(j \le n\) indica que a qualquer momento a soma das operações amortizadas é um limite superior ao custo real acumulado.
Poupança
A diferença entre o custo amortizado total acumulado e o custo real total acumulado é chamado de poupança acumulada (en: accumulated savings).
Ocasionalmente o custo de uma operação vai ser maior que o seu custo amortizado. Neste caso, retiramos a diferença da poupança.
A chave é mostrar que operações caras só ocorrem quando a diferença do custo pode ser paga pela poupança!
Créditos
Invariante
Todo crédito precisa ser alocado antes de ser usado e nenhum crédito pode ser usado mais de uma vez!
Normalmente para usar o método do banqueiro, define-se um invariante que garante que quando uma operação cara ocorrer então, há dinheiro suficiente na poupança para cobrir o custo.
head
tem custo amortizado 1 (e real também!)
snoc
r
está associado com \(1\) crédito.snoc
, gastamos um crédito para colocar o
elemento em r
e outro para deixar associado ao elemento
propriamente dito.
r
com \(n\) elementos tem \(n\) créditos
associados.snoc
é portanto \(2\)tail
tail
não precisar inverter a lista, ele custa 1 créditotail
precisar inverter a lista, ele precisará fazer \(n +
1\) passos, onde \(n\) é o tamanho da lista.
tail
, a poupança estará vazia e tail
terá tido um custo amortizado de \(1\) (\(n + 1 - n = 1\))Logo, como todas as operações têm custo amortizado \(\leq 2\), então qualquer sequência com \(n\) operações terá custo amortizado \(\leq 2n = O(n)\).
Não mostramos diretamente, mas é fácil mostrar que de fato \(\sum_{i=1}^{j} a_i \ge \sum_{i=1}^{j}\) vale.
link
.insert
(descontados os créditos da poupança) passa a ser
O(1).Estes slides foram preparados para os cursos de Paradigmas de Programação e Desenvolvimento Orientado a Tipos na UFABC.
Este material pode ser usado livremente desde que sejam mantidos, além deste aviso, os créditos aos autores e instituições.
Os método do banqueiro e do físico são equivalentes, mas por motivos de tempo nos concentraremos aqui apenas no método do banqueiro. Caso queira saber mais sobre o método cheque os livros [CO] e [CLRS]. Para a mesma demonstração que fazemos aqui para filas veja o capítulo 5 de [CO]. ↩︎
snoc
vem de cons
na ordem
inversa. Ninguém sabe exatamente quando isso surgiu, mas há
papers da década de 70 que já usam essa nomenclatura. ↩︎