作為 Codegym 大學課程一部分的導師授課片段。報名參加完整課程。
“你好,阿米戈!”
“你好,瑞希!”
“你已經對數組了解一兩件事,我希望你甚至設法解決了一些任務。但你並不是什麼都知道。例如,這是關於數組的另一個有趣的事實。數組不僅是一維的(線性的) ). 它們也可以是二維的。
“嗯……什麼意思?”
“這意味著數組的單元格不僅可以代表一列(或行),還可以代表一個矩形表格。
int[][]name = new int[width][height];
"其中name是數組變量的名稱,width是表格寬度(以單元格為單位),height是表格高度。看一個例子:
|
我們創建一個二維數組:2 列和 5 行。 我們在單元格 (1,1) 中寫入 5。 |
“這就是它在內存中的樣子:

“順便說一句,對於二維數組,你也可以使用快速初始化:
// Lengths of months of the year in each quarter
int[][] months = { {31, 28, 31}, {30, 31, 30}, {31, 31, 30}, {31, 30, 31} };
“嗯……現在這很有趣。如果我們想像在第一個內括號中代表一個元素,下一個是第二個……那麼二維數組就像數組的數組?”
“你真是個聰明的學生!沒錯。第一個元素是一維數組{31, 28, 31}
,第二個是{30, 31, 30}
,依此類推。但我們稍後會在本課中回過頭來討論這個問題。在那之前,試著想一想作為具有行和列的表格的二維數組,在每個交叉點形成單元格。
“我心裡有數了。順便問一下,這些二維陣列是乾什麼用的?”
“程序員經常需要二維數組。如果仔細觀察,幾乎所有棋盤遊戲都是使用現成的二維數組實現的:國際象棋、西洋跳棋、井字棋、海戰等:”

“我明白了!象棋或者海戰的比賽場地,完全適合二維陣法!”
“是的,但你需要使用數字作為單元格坐標。不是‘pawn e2-e4’,而是‘pawn (5,2) -> (5,4)’。作為程序員,這對你來說會更容易。 “
排列數組中的元素:(x, y) 或 (y, x)
“創建二維數組會引發一個有趣的難題。當我們使用創建數組時,我們有一個‘兩行5列new int [2][5];
’的表格還是‘兩列 5 行’?”
“換句話說,目前還不完全清楚我們是先指定寬度然後再指定高度……還是相反,先指定高度再指定寬度?”
“是的,這就是困境。而且沒有確定的答案。”
“該怎麼辦?”
“首先,重要的是要了解我們的二維數組實際上是如何存儲在內存中的。自然地,計算機內存中實際上並沒有任何表格:內存中的每個位置都有一個連續的數字地址:0、1、2, ...對我們來說,這是一個 2 × 5 的表格,但在內存中它只是 10 個單元格,僅此而已。沒有劃分行和列。”
“我明白了。那麼我們如何確定哪個尺寸在前——寬度還是高度?”
“讓我們考慮第一個選項。首先是寬度,然後是高度。”贊成這種方法的論據是這樣的:每個人在學校學習數學,他們都知道坐標對寫成'x'(即水平軸)然後是“y”(垂直維度)。這不僅僅是一個學校標準——它是一個普遍接受的數學標準。正如他們所說,你不能與數學爭論。”
「是嗎?好吧,既然打不過,那就先寬後高吧?」
“有一個支持‘先高後寬’的有趣論點。這個論點來自於二維數組的快速初始化。畢竟,如果我們想初始化我們的數組,那麼我們會這樣寫代碼:”
// Matrix of important data
int[][] matrix = { {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5} };
“那對我們有什麼用呢?”
“你有沒有註意到什麼?如果我們有這個怎麼辦?
// Matrix of important data
int[][] matrix = {
{1, 2, 3, 4, 5},
{1, 2, 3, 4, 5}
};
“如果我們在代碼中逐行寫入我們的數據,那麼我們會得到一個包含 2 行和 5 列的表格。”
“現在我明白了。2是高度,5是寬度……那麼我們應該使用哪個選項呢?”
“由你來決定哪個更方便。最重要的是所有從事同一個項目的程序員都堅持同一種方法。”
“如果你在一個項目中工作,它的代碼有很多初始化的二維數組,那麼很可能那裡的一切都基於快速數據初始化,即你將擁有標準的‘高度 x 寬度’。
“如果你發現自己在一個涉及大量數學和坐標的項目中(例如,遊戲引擎),那麼代碼很可能會採用“寬 x 高”的方法。
二維數組是怎麼排列的
“現在,你還記得你在課程開始時注意到的二維數組的特殊性嗎?”
“對!就是二維陣法,其實就是陣法的陣法!”
“完全正確。”換句話說,如果在普通數組的情況下,數組變量存儲對存儲數組元素的容器的引用,那麼在二維數組的情況下,情況有點爆炸:二維-array 變量存儲對容器的引用,該容器存儲對一維數組的引用。最好只看一次,而不是嘗試解釋一百遍:”

“在左邊,我們有一個二維數組變量,它存儲了對二維數組對象的引用。在中間有一個二維數組對象,其單元格存儲一維數組,這是二維數組的行。在右邊,你可以看到四個一維數組——我們的二維數組的行。這就是二維數組的實際工作方式。”
“太棒了!但它給了我們什麼?”
“由於‘容器的容器’存儲對‘行數組’的引用,我們可以非常快速、輕鬆地交換行。要獲得‘容器的容器’,您只需指定一個索引而不是兩個。示例:
int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];
“看下面的代碼。我們可以用它來交換行:”
|
二維數組matrix[0] 存儲對第一行的引用。我們交換參考。 結果, matrix 數組看起來像這樣:
|
“明白了。就像交換任意兩個普通物品一樣。”
“確實如此。好吧,如果你引用二維數組的一個單元格,但你只在數組名稱後指定一個索引,那麼你指的是一個容器的容器,其單元格存儲對普通一-維數組。”
“一切似乎都合乎邏輯且清晰。感謝您的演講,Rishi!”
“不客氣。明智地付諸實踐。”
GO TO FULL VERSION