Análise Amortizada? (Garantias de desempenho de pior caso)

12

O que é análise amortizada? E como isso pode me ajudar a obter as garantias de pior desempenho nos meus programas?

Eu estava lendo que as técnicas a seguir podem ajudar o programador a obter garantias de desempenho de pior caso (ou seja, em minhas próprias palavras: garantir que o tempo de execução de um programa não exceda o tempo de execução no pior elenco):

  • Algoritmos randomizados (por exemplo, o algoritmo quicksort é quadrático no pior dos casos, mas ordenar aleatoriamente a entrada fornece uma garantia probabilística de que seu tempo de execução é linearitmico)
  • Sequências de operações (nossa análise deve levar em conta os dados e a sequência de operações executadas pelo cliente)
  • Análise Amortizada (outra maneira de fornecer uma garantia de desempenho é amortizar o custo, mantendo o controle do custo total de todas as operações, dividido pelo número de operações. Nesse cenário, podemos permitir algumas operações caras, mantendo o custo médio Em outras palavras, distribuímos o custo de poucas operações caras, atribuindo uma parte dela a cada um de um grande número de operações baratas)

O autor mencionou o uso de redimensionar a estrutura de dados da matriz para Stack como um exemplo de como obter análise amortizada, mas ainda não entendo o que é a análise amortizada e como ela pode realmente ser implementada (estrutura de dados? Algoritmo?) Para obter o pior desempenho. garantias de desempenho

Anthony
fonte

Respostas:

13

Você não implementa análise amortizada. É uma técnica para obter Olimites mais precisos .

A observação essencial que você deve fazer é que operações caras não podem acontecer a qualquer momento.

No caso de uma estrutura de dados respaldada por matriz, a matriz precisa ser redimensionada de vez em quando - quando estiver cheia. Esta é a operação mais cara e leva O(n)tempo. Todas as outras inserções na matriz são O(1).

Para determinar o tempo de execução para inserir nitens, você pode multiplicar npela operação mais cara O(n), o que resulta em um comportamento geral de tempo de execução O(n^2).

No entanto, isso é impreciso, pois o redimensionamento não pode acontecer com muita frequência.

Ao falar sobre dinheiro, você amortiza o custo quando paga sua dívida com vários pequenos pagamentos ao longo do tempo.

Podemos usar esse modelo para pensar em algoritmos também. Simplesmente substituímos "tempo" por "dinheiro" para evitar o mapeamento mental.

nQuando a matriz estiver cheia , podemos dobrar seu tamanho. Precisamos fazer as seguintes operações:

  • Alocar 2npedaços de memória
  • copiar nitens

Se assumirmos que a alocação de memória e a cópia ocorrem em tempo linear, esta será uma operação muito cara. No entanto, agora podemos usar a ideia de dívida e amortizá-la para nossa análise. Somente amortizaremos nossa dívida antes de efetivamente fazê-la.
Vamos supor que nosso saldo (de dinheiro / tempo) retorne a 0 (ou seja, não temos dívidas nem sobras) depois de redimensionar a matriz.

Isso tem as seguintes implicações:

  • A inserção dos próximos nitens cobrirá o custo de redimensionamento e cópia ( nusamos slots e slots nnão utilizados »)

Agora podemos pensar em quanto cada operação de pastilha precisa pagar:

  • A inserção
  • O custo de alocar um pedaço de memória
  • o custo de movê-lo para a memória recém-alocada

Agora cobrimos os custos para alocar memória, copiar e inserir os próximos nelementos. No entanto, negligenciamos a alocação de espaço para os nelementos antigos , além de copiá-los.

Simplesmente distribuímos os custos de nossos nelementos antigos para nossos novos elementos (ainda a serem inseridos) n:

  • O custo de alocar um pedaço de memória
  • o custo de movê-lo para a memória recém-alocada

No total, todas as operações de pastilhas custam 5 unidades. Isso vale por sua própria inserção e pela movimentação e alocação de espaço para si e para um dos elementos antigos.

Toda operação de inserção ainda leva um tempo constante, mas o redimensionamento ocorre de graça: nós a amortizamos gastando "mais" tempo em cada inserção.

Como resultado, inserir nelementos leva O(n)tempo.

Outras técnicas para análise amortizada são explicadas aqui .

phant0m
fonte
1

Primeiro de tudo: é uma técnica para analisar os tempos de execução do programa, não uma técnica de implementação para algoritmos.

O exemplo mencionado em sua lista é bom: Anexando um único item à estrutura de dados respaldada por matriz. Para cada operação de acréscimo, o pior caso é ter que copiar todos os itens existentes. Esse tipo de análise é muito pessimista, pois você não precisa fazer isso se estiver usando uma estratégia de redimensionamento sensato (multiplicando o tamanho por alguns x> 1,0). A análise diz então que você tem um limite de O (n ^ 2) - O (n) por item vezes n itens - enquanto o tempo de execução real é apenas O (n).

Se você calcula a média do custo de redimensionamento de todos os itens inseridos (a maioria dos quais não precisa de redimensionamento), você está fazendo uma análise amortizada. A análise amortizada resulta em um limite O (n) que corresponde ao comportamento real do algoritmo.

Patrick
fonte