多維矩陣降維
December 12, 2021有時為了運算方便或儲存時空間問題,會將多維矩陣降維,例如,是將多面體的頂點攤平,並結合頂點索引來定義多面體,或者將上三角、下三角或對角矩陣降一維陣列,以節省空間,
解法思路
以二維陣列轉一維陣列為例,索引由 0 開始,看要以列為主(row-major)或以行為主(column-major)。
- 以列為主的二維陣列要降為一維時,是將二維陣列由上往下,逐列寫入一維陣列,此時索引的對應公式如下,其中
row
與column
是二維陣列索引,loc
表示對應的一維陣列索引: -
loc = column + row * 行數
- 以行為主的二維陣列要降為一維時,是將二維陣列由左往右,逐行寫入一維陣列,此時索引的對應公式如下:
-
loc = row + column * 列數
- 若是三維陣列,公式如下,其中
i
(個數u1
)、j
(個數u2
)、k
(個數u3
)分別表示三維陣列的三個索引: - 以列為主:loc = i * u2 * u3 + j * u3 + k
- 以行為主:loc = k * u1* u2 + j * u1 + i
更高維度的可以自行類推,不過更高維度時,建議使用其他資料結構,比較具體也不易搞錯。
程式實作
#include <stdio.h>
#include <stdlib.h>
#define ROW 3
#define COLUMN 4
void toOneByRow(int[][], int[]);
void toOneByColumn(int[][], int[]);
int indexByRow(int, int);
int indexByColumn(int, int);
void toOne(int[][COLUMN], int[], int (*)(int, int));
int main(void) {
int arr1[ROW][COLUMN] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};
int arr2[ROW * COLUMN] = {0};
printf("原二維資料:\n");
int row, column;
for(row = 0; row < 3; row++) {
for(column = 0; column < 4; column++) {
printf("%4d", arr1[row][column]);
}
printf("\n");
}
printf("\n以列為主:");
toOneByRow(arr1, arr2);
int i;
for(i = 0; i < 12; i++)
printf("%d ", arr2[i]);
printf("\n以行為主:");
toOneByColumn(arr1, arr2);
for(i = 0; i < 12; i++)
printf("%d ", arr2[i]);
printf("\n");
return 0;
}
void toOneByRow(int arr1[][COLUMN], int arr2[]) {
toOne(arr1, arr2, indexByRow);
}
void toOneByColumn(int arr1[][COLUMN], int arr2[]) {
toOne(arr1, arr2, indexByColumn);
}
int indexByRow(int row, int column) {
return column + row * COLUMN;
}
int indexByColumn(int row, int column) {
return row + column * ROW;
}
void toOne(int arr1[][COLUMN], int arr2[], int (*index)(int, int)) {
int row, column;
for(row = 0; row < ROW; row++) {
for(column = 0; column < COLUMN; column++) {
arr2[index(row, column)] = arr1[row][column];
}
}
}
public class Matrix {
public static int[] toOneByRow(final int[][] array) {
return toOne(array, new Index() {
public int get(int row, int column) {
return column + row * array[0].length;
}
});
}
public static int[] toOneByColumn(final int[][] array) {
return toOne(array, new Index() {
public int get(int row, int column) {
return row + column * array.length;
}
});
}
private static interface Index {
int get(int row, int column);
}
private static int[] toOne(int[][] array, Index index) {
int[] arr = new int[array.length * array[0].length];
for(int row = 0; row < array.length; row++) {
for(int column = 0; column < array[0].length; column++) {
arr[index.get(row, column)] = array[row][column];
}
}
return arr;
}
}
def toOneByRow(array):
return toOne(array, (lambda row, column: column + row * len(array[0])))
def toOneByColumn(array):
return toOne(array, (lambda row, column: row + column * len(array)))
def toOne(array, f):
arr = [0] * (len(array) * len(array[0]))
for row in range(len(array)):
for column in range(len(array[0])):
arr[f(row, column)] = array[row][column]
return arr
object Matrix {
def toOneByRow(array: Array[Array[Int]]) = {
toOne(array, _ * array(0).length + _)
}
def toOneByColumn(array: Array[Array[Int]]) = {
toOne(array, _ + _ * array.length)
}
private def toOne(array: Array[Array[Int]], f: (Int, Int) => Int) = {
val arr = new Array[Int](array.length * array(0).length)
for(row <- 0 until array.length; column <- 0 until array(0).length) {
arr(f(row, column)) = array(row)(column)
}
arr
}
}
def toOneByRow(array)
toOne(array) { |row, column| column + row * array[0].length }
end
def toOneByColumn(array)
toOne(array) { |row, column| row + column * array.length }
end
def toOne(array)
arr = Array.new(array.length * array[0].length, 0)
array.length.times { |row|
array[0].length.times { |column|
arr[yield(row, column)] = array[row][column]
}
}
arr
end
function toOneByRow(array) {
return toOne(array, (row, column) => column + row * array[0].length);
}
function toOneByColumn(array) {
return toOne(array, (row, column) => row + column * array.length);
}
function toOne(array, f) {
arr = []
for(let row = 0; row < array.length; row++) {
for(let column = 0; column < array[0].length; column++) {
arr[f(row, column)] = array[row][column];
}
}
return arr
}
let array = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
];
console.log(toOneByRow(array));
console.log(toOneByColumn(array));
import Data.List
toOneByRow matrix = [elem | row <- matrix, elem <- row]
toOneByColumn matrix = [elem | row <- transpose matrix, elem <- row]
main =
let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
in do
print $ toOneByRow matrix
print $ toOneByColumn matrix