Análise Amortizada Análise Amortizada Fernando Lobo Algoritmos e Estrutura de Dados II Resulta da análise de uma sequência de operações numa estrutura de dados. Apesar de uma operação individual poder ser dispendiosa, o objectivo é mostrar que em média o custo por operação é pequeno. Porque há poucas operações dispendiosas e muitas operações baratas. Análise Amortizada permite obter a complexidade no pior caso para uma qualquer sequência de operações. 1 / 35 2 / 35 Vários métodos Exemplo: Tabelas dinâmicas Existem vários métodos para fazer este tipo de análise. Vamos estudar três: 1. Método de análise agregada (aggregate analysis) 2. Método contabiĺıstico (accounting method) 3. Método do potencial (potencial method) Problema: Queremos ter uma tabela (por exemplo uma tabela de hash) mas não sabemos à partida quantos elementos é que a tabela poderá ter. A tabela deve ser o mais pequena possível (para não desperdiçar memória), mas também suficientemente grande para não haver overflow (ou sobrecarga no caso de uma tabela de hash). Como resolver o problema? 3 / 35 4 / 35
Exemplo: Tabelas dinâmicas Exemplo Uma solução possível: Começamos com uma tabela pequena. Se encher, criamos uma tabela nova (com malloc ou new) e copiam-se os elementos da tabela pequena para a tabela grande. Depois elimina-se a tabela pequena (com free ou delete). Começamos com uma tabela com apenas uma posição. Vamos inserindo elementos. Se a tabela encher, duplicamos o tamanho. 5 / 35 6 / 35 INSERT(1) INSERT(2) Deu overflow. A tabela está cheia. O próximo INSERT não vai caber. Cria-se uma tabela com o dobro do tamanho, copia-se os elementos da tabela antiga, insere-se o novo elemento, e apaga-se a tabela antiga. A nova tabela passa a ter dimensão 2 e contém 2 elementos: 1 e 2. Está cheia novamente. 7 / 35 8 / 35
INSERT(3) INSERT(4) Deu overflow. Cria-se uma tabela com o dobro do tamanho, copia-se os elementos da tabela antiga, insere-se o novo elemento, e apaga-se a tabela antiga. A nova tabela passa a ter dimensão 4 e contém 3 elementos: 1, 2, 3. 9 / 35 Não há problema. Insere-se 4. A tabela passa a ter 4 elementos e está novamente cheia. 10 / 35 INSERT(5) INSERT(6) Overflow. Cria-se uma tabela com o dobro do tamanho,... A nova tabela passa a ter dimensão 8 e contém 5 elementos. 11 / 35 Não há problema. Insere-se 6. A tabela passa a ter 6 elementos. 12 / 35
INSERT(7), INSERT(8),... Análise do pior caso Consideremos uma sequência de n INSERTs. Estão a ver a ideia. Não é necessário dizer mais nada... No pior caso, um INSERT é Θ(n). Logo, no pior caso n INSERTs é n Θ(n) = Θ(n 2 ) Certo? ERRADO! No pior caso, n INSERTs é apenas Θ(n). 13 / 35 14 / 35 Análise detalhada Mais fácil de ver um padrão se reescrevermos c i Seja c i = custo do i-ésimo INSERT. c i = { i, se i 1 = 2 k, k N 1, caso contrário i 1 2 3 4 5 6 7 8 9 10... size i 1 2 4 4 8 8 8 8 16 16... c i 1 2 3 1 5 1 1 1 9 1... c i 1 1+1 1+2 1 1+4 1 1 1 1+8 1... i 1 2 3 4 5 6 7 8 9 10... size i 1 2 4 4 8 8 8 8 16 16... c i 1 2 3 1 5 1 1 1 9 1... Custo de n INSERTs = c i size i é o tamanho da tabela imediatamente após o i-ésimo INSERT. =? 15 / 35 16 / 35
Custo de n INSERTs Análise Amortizada Custo de n INSERTs = c i lg(n 1) = n + = 3n n + 2n = Θ(n). j=0 2 j Qualquer estratégia que permita analisar uma sequência de operações e mostre que o custo médio de uma operação é pequeno (apesar de poder haver operações individuais que são caras) denomina-se de análise amortizada. Logo, o custo médio de cada operação é Θ(n) n = Θ(1). Ao custo médio chamamos custo amortizado. 17 / 35 18 / 35 Análise Amortizada Análise agregada Apesar de estarmos a fazer médias, isto não tem nada que ver com a análise de complexidade no caso médio. A análise não envolve probabilidades/distribuição de inputs. Análise amortizada dá a performance no pior caso para uma sequência de operações, o que é igual à performance média de cada operação no pior caso. O método que usamos há pouco é o método de análise agregada. Vejamos a análise do mesmo problema com os outros métodos: método contabiĺıstico. método potencial. 19 / 35 20 / 35
Método contabiĺıstico Método contabiĺıstico É a visão do banqueiro. O banco não dá juros. E também não dá empréstimos. A ideia é cobrar um custo fictício ĉ i (custo amortizado) pela operação. 1 Euro corresponde a uma unidade de trabalho (tempo). Isto é, o saldo do banco não pode ser negativo. Ou seja: Esse montante pode ser consumido ao efectuar-se a operação. O que sobrar guarda-se no banco para poder ser usado mais tarde. c i }{{} custo real ĉ i }{{} custo amortizado, n. 21 / 35 22 / 35 Cobrar um custo fictício de 3 Euros para cada INSERT. 1 Euro é para o INSERT propriamente dito. 2 Euros é para guardar no banco e usar mais tarde quando for necessário duplicar o tamanho da tabela. 1 Euro para mover um item recente. 1 Euro para mover um item antigo. Ver exemplo: 23 / 35 24 / 35
Invariante: O saldo do banco 0. Logo, a soma dos custos amortizados é um limite superior para a soma dos custos reais. Ao inserir o 9 o elemento temos de duplicar o tamanho da tabela. Os 8 Euros que estão no banco dão para mover os 8 elementos na tabela antiga para a tabela nova. i 1 2 3 4 5 6 7 8 9 10... size i 1 2 4 4 8 8 8 8 16 16... c i 1 2 3 1 5 1 1 1 9 1... ĉ i 2 3 3 3 3 3 3 3 3 3... bank i 1 2 2 4 2 4 6 8 2 4... Depois o banco fica com zero Euros. etc... 25 / 35 26 / 35 Método potencial i 1 2 3 4 5 6 7 8 9 10... size i 1 2 4 4 8 8 8 8 16 16... c i 1 2 3 1 5 1 1 1 9 1... ĉ i 2 3 3 3 3 3 3 3 3 3... bank i 1 2 2 4 2 4 6 8 2 4... A primeira operação só necessita de 2 Euros. Mas se dermos 3 Euros também não faz mal. Fazemos o banco ficar com 1 Euro a mais. É uma esmola. Coitados dos bancos É a visão do físico. A ideia é olhar para o montante que está na conta bancária como se fosse energia. A energia fica associada à estrutura de dados no seu todo. 27 / 35 28 / 35
Método potencial Método potencial Começamos com uma estrutura de dados D 0. Operação i transforma D i 1 em D i. Custo real da operação i é c i. Definimos uma função potencial, Φ : {D i } R, de tal forma que: Φ(D 0 ) = 0 Φ(D i ) 0, i O custo amortizado ĉ i é definido por, ĉ i = c i + Φ(D i ) Φ(D i 1 ) }{{} dif. de potencial Φ i Se Φ i > 0, então ĉ i > c i. operação i guarda energia na E.D. para poder usar mais tarde. Se Φ i < 0, então ĉ i < c i. a E.D. gasta energia armazenada para ajudar a pagar o custo real da operação i. 29 / 35 30 / 35 Método potencial O custo amortizado total das n operações é: Definimos o potencial da tabela imediatamente após o i-ésimo INSERT por: Φ(D i ) = 2i 2 lg i (assumir que 2 lg 0 = 0) ĉ i = = (c i + Φ(D i ) Φ(D i 1 )) ( ) c i + Φ(D n ) Φ(D 0 ) c i, porque Φ(D n ) 0 e Φ(D 0 ) = 0 Nota: Φ(D 0 ) = 0 e Φ(D i ) 0, i 31 / 35 32 / 35
Custo amortizado da i-ésima operação é: Análise por casos ĉ i = c i + Φ(D i ) Φ(D i 1 ) { i, se i 1 for uma potência exacta de 2 = 1, caso contrário ( + 2i 2 lg i ) (2(i 1) 2 lg(i 1) ) = {...} + 2 2 lg i + 2 lg(i 1). } Caso 1: i 1 é uma potência exacta de 2. ĉ i = i + 2 2 lg i + 2 lg(i 1) = i + 2 2(i 1) + (i 1) = i + 2 2i + 2 + i + 1 = 3. Caso 2: i 1 não é uma potência exacta de 2. ĉ i = 1 + 2 2 lg i + 2 lg(i 1) = 3. (porque neste caso 2 lg i = 2 lg(i 1) ) Logo, n INSERTs custam 3n = Θ(n), no pior caso. 33 / 35 34 / 35 Qual o método a utilizar na prática? Pode-se usar qualquer método (agregado, contabiĺıstico, potencial). Há situações em que um método pode ser mais apropriado (i.e., mais fácil de aplicar) que outro. 35 / 35