Quantas cópias são necessárias para aumentar uma matriz?


8

Estou lendo uma análise sobre matrizes dinâmicas (do manual do algoritmo do Skiena).
Ou seja, quando temos uma estrutura de matriz e cada vez que estamos sem espaço, alocamos uma nova matriz com o dobro do tamanho do original.

Ele descreve o desperdício que ocorre quando a matriz precisa ser redimensionada.
Diz que (n / 2) +1 a n será movido no máximo uma vez ou não será. Isto está claro.
Em seguida, descrevendo que metade dos elementos se move uma vez, um quarto dos elementos duas vezes e assim por diante, o número total de movimentos M é dado por:

insira a descrição da imagem aqui

Parece-me que adiciona mais cópias do que realmente acontece.

Por exemplo

se tivermos o seguinte:

array of 1 element
+--+
|a |
+--+

double the array (2 elements)  
+--++--+  
|a ||b |  
+--++--+  

double the array (4 elements)  
+--++--++--++--+  
|a ||b ||c ||c |  
+--++--++--++--+  

double the array (8 elements)  
+--++--++--++--++--++--++--++--+    
|a ||b ||c ||c ||x ||x ||x ||x |  
+--++--++--++--++--++--++--++--+    

double the array (16 elements)  
+--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--+    
|a ||b ||c ||c ||x ||x ||x ||x ||  ||  ||  ||  ||  ||  ||  ||  |   
+--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--+   

Temos o elemento x copiado 4 vezes, o elemento c copiado 4 vezes, o elemento b copiado 4 vezes e um elemento copiado 5 vezes, de modo que o total é 4 + 4 + 4 + 5 = 17 cópias / movimentos.

Mas, de acordo com a fórmula, deveríamos ter 1 * (16/2) + 2 * (16/4) + 3 * (16/8) + 4 * (16/16) = 8 + 8 + 6 + 4 = 26 cópias de elementos para a ampliação da matriz para 16 elementos.

Isso é algum erro ou o objetivo da fórmula é fornecer uma aproximação aproximada do limite superior? Ou estou entendendo algo errado aqui?


Outro fator: no mundo real, os elementos alocados vazios seriam zerados (em uma linguagem de alto nível como Java ou C #). Isso implica uma gravação (mas não uma leitura), que parece custar metade do que uma cópia.
dbkk

1
Suas somas não estão corretas; bé copiado 3 vezes, cada cduas vezes e uma xvez. 15 cópias.
Donal Fellows

Respostas:


5

Primeiro, b é movido 3 vezes e a é movido 4 vezes, o que fornece um total de 4 + 4 + 3 + 4 = 15 cópias.

Eu acho que a fórmula deve ser preenchida com n = 8: 1 * (8/2) (x é copiado uma vez) + 2 * (8/4) (c é copiado duas vezes) + 3 * (8/8) (b é copiado três vezes) = 11. Em outras palavras, a fórmula parece estar faltando um termo "+ log 2 n + 1" além da soma em si.

O que me parece ser uma maneira muito mais natural de contar o número de movimentos é contar o número de elementos movidos por cópia:

soma de i = 1 a i = teto (log 2 n): 2 i-1

No seu caso, n = 16, então teto (log 2 16) = 4 e a soma acima é: 2 0 +2 1 +2 2 +2 3 = 1 + 2 + 4 + 8 = 15.

Vou ver se consigo encontrar este manual do algoritmo do Skiena para ver se o corrigi.

Atualização: Encontrei a peça no manual do algoritmo de Skiena. Parece que falta um termo na soma que ele usa lá. No entanto, a conclusão está correta:

M = soma de i = 1 a i = teto (log 2 n): 2 i-1 = soma de i = 0 a i = teto (log 2 n) - 1: 2 i = 2 teto (log 2 n) - 1 + 1 <= (2 log 2 n + 1-1 + 1 ) = 2 * n

(Gostaria de poder formatar essas fórmulas de uma maneira mais agradável para você)

O ponto principal deste parágrafo parece ser o exemplo de análise amortizada . Métodos como o método potencial criariam um argumento melhor (menos ad hoc) por que as matrizes dinâmicas funcionam muito bem, mas esse método é um pouco avançado.

Se você está convencido de que há um erro neste livro, considere entrar em contato com o autor sobre isso (de uma maneira construtiva, é claro - o livro tem muitas páginas, e é difícil corrigir tudo o que há de mais atual e sempre há uma chance de o livro estar certo e nós dois errarmos). Eu não encontrei este em particular na errata.


Eu formatei as fórmulas um pouco :-)
Péter Török

Obrigado, parece muito melhor agora - estou acostumado à formatação do LaTeX e não acho que isso seja possível no Programmers.SE.
Alex10 Brink #

@Alex: +1 obrigado por this.I estava me perguntando por que você acha que no OP o n deve ser 8 e não 16.Eu não entendi.
user10326

Como os termos i * n / 2 ^ i fazem sentido: se i = 1, você fala sobre 1 * n / 2, o que corresponderia à metade da entrada que está sendo copiada uma vez. No exemplo dele, há quatro posições x que são copiadas uma vez e 8/2 = 4, então n = 8 faria mais sentido. Se n = 16, 16/2 = 8 elementos supostamente seriam copiados uma vez, o que simplesmente não corresponde ao exemplo.
Alex10 Brink

2

Nos níveis mais baixos de contagem de blocos, é improvável que ocorra uma alocação de memória. Os gerenciadores de memória lidam com blocos de memória e alocam rotineiramente blocos maiores de memória do que a solicitação de alocação solicitada automaticamente.

Da mesma forma, a implementação de uma classe de matriz provavelmente arredondará alocações para permitir alguns elementos adicionais.

EDITAR:

Em uma reflexão mais aprofundada, é improvável que as cópias reais ocorram conforme você as descreve. Os processadores geralmente possuem um comando de cópia de bloco e usariam uma única instrução de montagem para copiar os dados da matriz como um único bloco de memória para o novo endereço.


1
Desculpe, como isso está relacionado à minha pergunta?
user10326

Bem, se uma alocação não precisar ocorrer, não será necessário copiar os elementos da matriz para o novo espaço de memória.
Michael Shaw

1
Mas estou perguntando sobre a fórmula.
user10326

Fair o suficiente, é uma questão matemática e eu estou dando respostas de programação em um site de programação ...;)
Michael Shaw

0

Eu acredito que a fórmula dada no livro é simplesmente incorreta. O imultiplicador deve ser retirado da fórmula para corrigi-lo.

Vamos pegar o exemplo do autor e chamar a matriz de 1 elemento matriz-1, a matriz de 2 elementos - array-2, a matriz de 4 elementos - array-4e assim por diante.

Portanto, de acordo com o livro, para este exemplo em particular, o número de cópias é regido pela seguinte fórmula:


M = 1⋅8 + 2⋅4 + 3⋅2 + 4⋅1

O primeiro termo da soma 1⋅8é para copiar array-8'sitens para array-16.

Copiamos os array-4'sitens (a, b, c, c)duas vezes. Uma vez do array-4para array-8. E então ao copiar array-8'sitens para array-16nós copiar (a, b, c, c)itens para o segundo tempo. Por conseguinte para o livro, por conseguinte, o segundo termo: 2⋅4.

Mas agora observe que o 1⋅8termo já leva em consideração a cópia de (a, b, c, c)itens de array-8para array-16. Consequentemente, o 2⋅4termo não deve incluir o 2multiplicador.

A mesma lógica se aplica a todos os outros termos. E assim, multiplicar por ié um erro.


você se importaria de explicar mais sobre o que faz e por que o recomenda como resposta à pergunta? "Respostas apenas para links" não são bem-vindas no Stack Exchange
gnat

Certo. Copiarei minha resposta de cs.stackexchange. O problema é que programmers.stackexchange não permite a formatação adequada de fórmulas matemáticas.
Nik

por minha leitura, as fórmulas em sua resposta ao CS pode ser razoavelmente aproximada usando o código de formatação com acentos graves: M=1⋅8+2⋅4+3⋅2+4⋅1etc
mosquito
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.