使用 Java 函數轉置 double[][] 矩陣
1. 概述
矩陣在程式設計中至關重要,無論是科學計算、圖形繪製或數據分析,都離不開它。在許多情況下,轉置操作是常用的,它透過交換行和列來重新排列資料。
在本教程中,我們將解釋矩陣轉置的含義,以及如何實現簡潔、可重複使用的 Java 方法來轉置double[][]矩陣。
2. 轉置矩陣的視覺化呈現
在學習如何在二維矩陣中翻轉資料之前,最好先看一個直觀的例子。
首先,我們建立一個 2×3 矩陣:
abc
def
目標是透過改變資料的位置來重新組織相同的資料。簡單來說,我們將矩陣沿著對角線翻轉,使每一行變成一列,每一列變成一行。
轉置後,矩陣應有三行兩列:
ad
be
cf
在此變換過程中,原矩陣中位置[row][column]的每個元素移動到第二個矩陣中的位置[column][row] 。例如,位置[0][1] ( b ) 的元素移動到位置[1][0] ,位置[1][0] ( d ) 的元素移動到[0][1] ,依此類推。
因此,我們最終從原來的 2×3 矩陣得到了一個 3×2 矩陣。
3. 簡單轉置函數
現在我們已經了解了矩陣轉置是什麼,讓我們看看如何在 Java 中實現它。
最簡單的方法是建立一個新矩陣,然後使用for迴圈將原始矩陣中的每個元素複製到新位置:
public static double[][] transpose(double[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
double[][] transposed = new double[cols][rows];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
transposed[j][i] = matrix[i][j];
}
}
return transposed;
}
首先,我們使用matrix.length和matrix[0].length來提取矩陣的行數和列數。然後,我們利用這些值來建立一個維度互換的新陣列。
接下來,嵌套迴圈遍歷原始數組,並將新矩陣中位置(i, j)到(j, i)的每個元素複製到新矩陣中。最後,我們直接傳回新建的矩陣。
這裡的目標是使該方法易於重用於任何double[][]矩陣,而不管其維度如何。
4. 原地轉置矩陣(僅限方陣)
我們先前探討的方法在大多數情況下效果良好,但對於對效能要求較高的應用來說可能並非理想之選。在這種情況下,我們可以直接修改原始矩陣,而無需分配額外的記憶體。但是,這種方法的前提是矩陣必須是方陣。
因此,如果行數和列數相同,我們可以放心地使用原地轉置方法:
public static void transposeInPlace(double[][] matrix) {
int n = matrix.length; // number of rows&columns
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
double temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
}
此函數透過交換主對角線上的元素來轉置方陣。內層循環從j = i + 1開始,因此只處理對角線以上的元素。所以,對角線上的元素( i == j )保持不變。
在每次迭代中,函數將(i, j)處的值保存在一個臨時變數中,將其替換為(j, i)處的值,然後將已儲存的值寫回相反的位置。
當兩個循環都結束後,函數會將對角線上方的每個元素與其下方的對應元素交換位置。這樣就能產生轉置矩陣,而無需分配新的記憶體。
5. 使用 Java Streams
我們可以使用 Java Streams 來描述轉置過程,而不是使用明確的巢狀循環。這種方法以清晰、函數式的風格表達了轉換過程。
想法很簡單: for each column, collect elements from all rows and turn them into a new row 。讓我們看看具體該怎麼做:
public static double[][] transposeStream(final double[][] matrix) {
return IntStream.range(0, matrix[0].length)
.mapToObj(col -> Stream.of(matrix)
.mapToDouble(row -> row[col])
.toArray()
)
.toArray(double[][]::new);
}
具體來說,我們需要從java.util.stream導入IntStream和Stream 。然後, IntStream.range產生矩陣的列索引。對於每一列, mapToObj透過遍歷現有行來建立一個新行。在這個流中, mapToDouble會提取目前列的值, toArray()將這些值收集到一個陣列中。最後, toArray(double[][]::new)將所有行合併成一個新的二維陣列(轉置後的矩陣)。
6. 結論
本文探討了矩陣轉置的概念以及如何在 Java 中實現它。我們首先介紹了一個基於迴圈的簡單解決方案,然後研究了針對方陣的原地轉置方法,最後介紹了一種使用 Java Streams 的函數式實作方法。
每種方法都有其優勢,因此最佳選擇取決於可讀性、效能和當前問題。
和以往一樣,所有原始碼都可以在 GitHub 上找到。