de una sola línea al final de esta respuesta, la explicación siguiente :-)
el co array eficiente tiene: M elementos para la primera fila (fila 0, en su indexación), (M-1) para el segundo (fila 1), y así sucesivamente, para un total de M + (M-1) + & hellip; + 1 = M (M + 1)/2 elementos.
Es un poco más fácil trabajar desde el final, debido a que la matriz de coeficiente de siempre tiene 1 elemento para la última fila (fila M-1), 2 elementos para la segunda última fila (fila M-2), 3 elementos para la fila M-3, y así sucesivamente.Las últimas K filas ocupan las últimas K (K + 1)/2 posiciones de la matriz de coeficientes.
Supongamos que se le asigna un índice i en la matriz de coeficientes. Hay elementos M (M + 1)/2-1-i en posiciones mayores que i. Llamar a este número i '; desea encontrar el mayor k tal que k (k + 1)/2 ≤ i '. La forma de este problema es la fuente de tu miseria; por lo que puedo ver, no puedes evitar tomar raíces cuadradas :-)
Bueno, hagámoslo de todos modos: k (k + 1) ≤ 2i 'significa (k + 1/2) - 1/4 ≤ 2i ', o equivalentemente k ≤ (sqrt (8i' + 1) -1)/2. Permítanme llamar a la k más grande como K, luego hay K filas que son posteriores (de un total de M filas), por lo que row_index (i, M) es M-1-K. En cuanto al índice de columna, K (K + 1)/2 elementos del i 'están en filas posteriores, entonces hay j' = i'-K (K + 1)/2 elementos posteriores en esta fila (que tiene K + 1 elementos en total), por lo que el índice de columna es K-j '. [O lo que es lo mismo, esta fila comienza en (K + 1) (K + 2)/2 desde el final, por lo que solo debemos restar la posición inicial de esta fila de i: i- [M (M + 1)/2 - (K + 1) (K + 2)/2]. Es alentador que ambas expresiones dan la misma respuesta]
(pseudo) Código [ii utilizando en lugar de i 'como algunos idiomas no permiten variables con nombres como i' ;-)]:
row_index(i, M):
ii = M(M+1)/2-1-i
K = floor((sqrt(8ii+1)-1)/2)
return M-1-K
column_index(i, M):
ii = M(M+1)/2-1-i
K = floor((sqrt(8ii+1)-1)/2)
return i - M(M+1)/2 + (K+1)(K+2)/2
Por supuesto que puede convertirlos en frases sencillas sustituyendo las expresiones para ii y K. Puede que tenga cuidado con los errores de precisión, pero hay formas de encontrar la raíz cuadrada entera que no requiere cálculo de punto flotante . Además, para citar a Knuth: "Cuidado con los errores en el código anterior, solo he demostrado que es correcto, no lo he probado".
Si me atrevo a hacer una observación adicional: simplemente mantener todos los valores en un M × matriz M tomará como máximo el doble de memoria, y dependiendo de su problema, el factor de 2 podría ser insignificante en comparación con las mejoras algorítmicas , y valdría la pena comerciar con el cálculo posiblemente caro de la raíz cuadrada para las expresiones más simples que tendrá.
[Editar: Por cierto, puede probar ese piso ((sqrt (8ii + 1) -1)/2) = (isqrt (8ii + 1) -1)/2 donde isqrt (x) = piso (sqrt (x)) es una raíz cuadrada entera, y la división es una división entera (truncamiento, el valor predeterminado en C/C++/Java, etc.) - por lo que si le preocupan los problemas de precisión, solo tiene que preocuparse por implementar un número entero correcto raíz cuadrada.]
¿Puede usted reformular eso para que los elementos en la matriz sean quizás letras en vez? que los números: es difícil comprender al 100% exactamente qué se supone que deben hacer sus funciones cuando utiliza valores de fila/col basados en cero y valores basados en uno en la matriz misma. – Alnitak
@Alnitak: hecho. –
data [row * num_cols + column] es la expresión clásica para una matriz C 2D almacenada en la memoria como una única matriz. –