¿Cuántas copias se necesitan para ampliar una matriz?

8

Estoy leyendo un análisis sobre matrices dinámicas (del manual de algoritmos de Skiena).
Es decir, cuando tenemos una estructura de matriz y cada vez que nos quedamos sin espacio, asignamos una nueva matriz del doble del tamaño del original.

Describe el desperdicio que ocurre cuando la matriz tiene que ser redimensionada.
Dice que (n / 2) +1 a n se moverán como máximo una vez o no se moverán. Esto esta claro.
Luego, al describir que la mitad de los elementos se mueven una vez, una cuarta parte de los elementos dos veces, y así sucesivamente, el número total de movimientos M viene dado por:

ingrese la descripción de la imagen aquí

Esto me parece que agrega más copias de las que realmente suceden.

P.ej

si tenemos lo siguiente:

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 ||  ||  ||  ||  ||  ||  ||  ||  |   
+--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--+   

Tenemos el elemento x copiado 4 veces, el elemento c copiado 4 veces, el elemento b copiado 4 veces y un elemento copiado 5 veces, por lo que el total es 4 + 4 + 4 + 5 = 17 copias / movimientos.

Pero de acuerdo con la fórmula, deberíamos tener 1 * (16/2) + 2 * (16/4) + 3 * (16/8) + 4 * (16/16) = 8 + 8 + 6 + 4 = 26 copias de elementos para la ampliación de la matriz a 16 elementos.

¿Es esto un error o el objetivo de la fórmula es proporcionar una aproximación aproximada del límite superior? ¿O estoy entendiendo mal algo aquí?

usuario10326
fuente
Otro factor: en el mundo real, los elementos asignados vacíos se pondrían a cero (en un lenguaje de alto nivel como Java o C #). Esto implica una escritura (pero no una lectura), que parece costar la mitad que una copia.
dbkk
1
Tus sumas no son correctas; bse copia 3 veces, cada cdos veces y cada xuna. 15 ejemplares.
Donal Fellows

Respuestas:

5

En primer lugar, b se mueve 3 veces y a se mueve 4 veces, lo que da un total de 4 + 4 + 3 + 4 = 15 copias.

Creo que la fórmula se debe completar con n = 8: 1 * (8/2) (x se copia una vez) + 2 * (8/4) (c se copia dos veces) + 3 * (8/8) (b se copia tres veces) = 11. En otras palabras, a la fórmula parece faltarle un término "+ log 2 n + 1" además de la suma misma.

Lo que me parece una forma mucho más natural de contar el número de movimientos es contar el número de elementos movidos por copia:

suma de i = 1 a i = techo (log 2 n): 2 i-1

En su caso, n = 16, entonces techo (log 2 16) = 4 y la suma anterior es: 2 0 +2 1 +2 2 +2 3 = 1 + 2 + 4 + 8 = 15.

Veré si puedo encontrar el manual de algoritmos de este Skiena para ver si lo tengo correcto.

Actualización: encontré la parte en el manual del algoritmo de Skiena. Parece que falta un término en la suma que usa allí. Sin embargo, la conclusión es correcta:

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

(Desearía poder formatear estas fórmulas de una manera más agradable para ti)

El punto principal de este párrafo parece ser dar un ejemplo de análisis amortizado . Métodos como el método potencial podrían hacer un argumento mejor (menos ad hoc) por qué los arreglos dinámicos funcionan muy bien, pero este método es algo avanzado.

Si está convencido de que hay un error en este libro, podría considerar ponerse en contacto con el autor al respecto (de una manera constructiva, por supuesto, el libro tiene muchas páginas y es difícil corregir hasta el último detalle, y siempre hay un posibilidad de que el libro sea correcto y los dos nos equivoquemos). No he encontrado este en particular en la errata.

Alex ten Brink
fuente
Formateé un poco las fórmulas :-)
Péter Török
Gracias, ahora se ve mucho mejor: estoy acostumbrado al formato LaTeX y no creo que sea posible en Programmers.SE.
Alex ten Brink
@ Alex: +1 gracias por esto. Me preguntaba por qué crees que en el OP el n debería ser 8 y no 16. No entendí eso.
user10326
Porque entonces los términos i * n / 2 ^ i tienen sentido: si i = 1, entonces se habla de 1 * n / 2, que correspondería a la mitad de la entrada que se copia una vez. En su ejemplo, hay cuatro posiciones x que se copian una vez, y 8/2 = 4, por lo que n = 8 tendría más sentido. Si n = 16, entonces 16/2 = 8 elementos supuestamente se copiarían una vez, lo que simplemente no coincide con el ejemplo.
Alex ten Brink
2

En los niveles más bajos de conteo de bloques, es poco probable que ocurra una asignación de memoria. Los administradores de memoria manejan bloques de memoria y asignan rutinariamente bloques de memoria más grandes que la solicitud de asignación solicitada actualmente.

Del mismo modo, es probable que la implementación de una clase de matriz redondee las asignaciones para permitir algunos elementos adicionales.

EDITAR:

En una reflexión posterior, es poco probable que las copias reales ocurran como las describe. Los procesadores generalmente tienen un comando de copia en bloque y usarían una sola instrucción de ensamblador para copiar los datos de la matriz como un solo bloque de memoria a la nueva dirección.

Michael Shaw
fuente
1
Lo sentimos, ¿cómo se relaciona esto con mi pregunta?
user10326
Bueno, si no es necesario que se produzca una asignación, no hay necesidad de copiar los elementos de la matriz en el nuevo espacio de memoria.
Michael Shaw
1
Pero estoy preguntando sobre la fórmula.
user10326
Es justo, es una pregunta matemática y estoy dando respuestas de programación en un sitio de programación ...;)
Michael Shaw
0

Creo que la fórmula dada en el libro es simplemente incorrecta. El imultiplicador debe eliminarse de la fórmula para solucionarlo.

Tomemos el ejemplo del autor de la pregunta y llamemos a la matriz de 1 elemento matriz-1, la matriz de 2 elementos - array-2, la matriz de 4 elementos - array-4, y así sucesivamente.

Entonces, de acuerdo con el libro, para este ejemplo en particular, el número de copias se rige por la siguiente fórmula:


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

El primer término de la suma 1⋅8es para copiar array-8'selementos en array-16.

Copiamos los array-4'sartículos (a, b, c, c)dos veces. Una vez del array-4al array-8. Y luego, al copiar array-8'selementos array-16, copiamos (a, b, c, c)elementos por segunda vez. De acuerdo con el libro, por lo tanto, el segundo término: 2⋅4.

Pero ahora observe que el 1⋅8término ya tiene en cuenta la copia de (a, b, c, c)elementos de array-8a array-16. En consecuencia, el 2⋅4término no debe incluir el 2multiplicador.

La misma lógica se aplica a todos los demás términos. Y multiplicar por ies un error.

Nik
fuente
¿Le importaría explicar más sobre lo que hace y por qué lo recomienda como respuesta a la pregunta que se hace? "Enlace de sólo responde" no están muy bienvenida en la pila de Cambio
mosquito
Por supuesto. Copiaré mi respuesta de cs.stackexchange. Sin embargo, el problema es que programmers.stackexchange no permite el formato adecuado de fórmulas matemáticas.
Nik
Según mi lectura, las fórmulas en su respuesta al CS se pueden aproximar razonablemente utilizando el código de formato con acentos abiertos: M=1⋅8+2⋅4+3⋅2+4⋅1etc
mosquito