二維數組學習筆記

一、二維數組的定義

當一維數組元素的類型也是一維數組時,便構成了「數組的數組」,即二維數組。
二維數組定義的一般格式:

數據類型 數組名[常量表達式][常量表達式]

例如:

int a[4][10]

a數組實質上是一個有 \(4\) 行、 \(10\) 列的表格,表格中課存儲 \(40\) 個元素。第 \(1\) 行第 \(1\) 列對應 \(a\) 數組的 \(a[0][0]\),第n行第m列對應數組元素 \(a[n-1][m-1]\)

說明:當定義的數組下表有多個時,我們稱為多維數組,下標的個數並不局限在一個或兩個,可以任意多個,如定義一個三維數組 \(a\) 和四維數組 \(b\)

int a[5][3][10];
int b[100][100][20][5];

多維的數組引用賦值等操作與二維數組類似。

二、二維數組元素的引用

二維數組的數組元素引用於一位數組元素引用類似,區別在於二維數組元素的引用必須給出兩個下標。
引用的格式為:

<數組名>[下標1][下標2]

說明:顯然,每個下標表達式取值不應超出下標所指定的範圍,否則會導致致命的越界錯誤。
例如,設有定義:

int a[3][5];

則表示 \(a\) 是二維數組(相當於一個 \(3 \times 5\) 的表格),共有 \(3 \times 5 = 15\) 個元素,它們是:

a[0][0] a[0][1] a[0][2] a[0][3] a[0][4]
a[1][0] a[1][1] a[1][2] a[1][3] a[1][4]
a[2][0] a[2][1] a[2][2] a[2][3] a[2][4]

因此可以看成一個矩陣(表格),\(a[2][3]\) 即表示第 \(3\) 行第 \(4\) 列的元素。

三、二維數組的初始化

二維數組的初始化和一維數組類似。可以將每一行分開來寫在各自的括弧里,也可以把所有數據寫在一個括弧里。
例如:

int direct[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int direct[4][2] = { 1, 0, 0, 1, -1, 0, 0, -1 };

例1 對角線翻轉

題目描述

給你一個 \(n \times n\) 的二維數組,你需要對其按照對角線進行翻轉,並輸出翻轉後的二維數組。
例如,下面左邊是一個 \(3 \times 3\) 的二維數組,後邊是它按照對角線進行翻轉後的二維數組:

1 2 3                   1 4 7 
4 5 6                   2 5 8
7 8 9                   3 6 9

輸入格式

輸入的第一行包含一個整數 \(n(1 \le n \le 100)\)
接下來 \(n\) 行,每行包含 \(n\) 個整數,用於表示二維數組中的每個元素(每個元素均為 \(1000\) 以內的正整數)。

輸出格式

輸出 \(n\) 行,每行包含 \(n\) 個整數,兩兩之間以一個空格分隔,用於表示按對角線翻轉後的二維數組。

樣例輸入

3
1 2 3
4 5 6
7 8 9

樣例輸出

1 4 7
2 5 8
3 6 9

問題分析

我們假設數組 \(a[i][j]\) 用於表示原二維數組中第 \(i\) 行第 \(j\) 列的元素,而沿對角線翻轉後它的位置變到了第 \(j\) 行第 \(i\) 列。
所以,輸入的時候,我們開兩層for循環,外層循環遍歷行號 \(i\),內層循環遍歷列號 \(j\) ,輸入 \(a[i][j]\)
而輸出的時候,我們開兩層for循環,外層循環遍歷列號 \(j\),內層循環遍歷行號 \(i\),輸出 \(a[i][j]\) 即可。

示例程式碼:

#include <bits/stdc++.h>
using namespace std;
int n, a[100][100];
int main() {
    cin >> n;
    for (int i = 0; i < n; i ++)    // 輸入的時候先遍歷行號i,再遍歷列號j
        for (int j = 0; j < n; j ++)
            cin >> a[i][j];     // 輸入a[i][j]
    for (int j = 0; j < n; j ++) {  // 輸出的時候先遍歷列號j,在遍歷行號i
        for (int i = 0; i < n; i ++) {
            if (i > 0) cout << " "; // 除了最前面那個元素以外的元素前先數一個空格,能保證兩兩之間以一個空格分隔
            cout << a[i][j];    // 輸出a[i][j]
        }
        cout << endl;   // 內層循環結束記得加一個回車
    }
    return 0;
}

例2 對角線增加

題目描述

已知一個 \(n \times n\) 的矩陣(方陣),把所有處在矩陣的兩條對角線上面的元素都加上 \(10\),然後輸出這個新矩陣。

輸入格式

輸入的第一行包含一個整數 \(n(1 \le n \le 100)\)
接下來 \(n\) 行,每行包含 \(n\) 個整數,用於表示二維數組中的每個元素(每個元素均為 \(1000\) 以內的正整數)。

輸出格式

輸出 \(n\) 行,每行包含 \(n\) 個整數,兩兩之間以一個空格分隔,用於表示兩條對角線上的元素都 \(+10\) 之後的矩陣。

樣例輸入

3
1 1 1
1 1 1
1 1 1

樣例輸出

11 1 11
1 11 1
11 1 11 

問題分析

首先我們假設行號和列號都從 \(0\) 開始,即左上角的元素為 \(a[0][0]\),右下角的元素為 \(a[n-1][n-1]\),然後我們去遍歷每一行(假設行號是 \(i\)),那麼只有列號 \(j\) 滿足條件 \(j==i\) 或者 \(j == n-1-i\) 的格子上的元素需要 \(+10\)
當然我們要注意,當 \(n\) 為奇數時,中間的那個點 \(a[n/2][n/2]\) 同時處在了兩條對角線上,但是只需要加一遍即可。
示例程式碼如下:

#include <bits/stdc++.h>
using namespace std;
int n, a[100][100];
int main() {
    cin >> n;
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < n; j ++)
            cin >> a[i][j];
    for (int i = 0; i < n; i ++) {
        if (i == n-1-i) // 說明第i行兩條對角線上的點重疊了
            a[i][i] += 10;  // 所以只需要給這一個點+10即可
        else {          // 否則,需要給兩個點依次+10
            a[i][i] += 10;
            a[i][n-1-i] += 10;
        }
    }
    for (int i = 0; i < n; i ++) {
        for (int j = 0; j < n; j ++) {
            if (j) cout << " ";
            cout << a[i][j];
        }
        cout << endl;
    }
    return 0;
}

例3 稀疏矩陣存儲方案

題目描述

大部分元素是 \(0\) 的矩陣稱為 稀疏矩陣 ,假設有 \(k\) 個非 \(0\) 元素,則可把稀疏矩陣用 \(k \times 3\) 的矩陣簡記之,其中第一列是行號,第二列是列號,第三列是該行、該列下的非零元素的值。如:

0 0 0 5             簡記為:  1 4 5   // 第1行第4列有一個5
0 2 0 0                     2 2 2   // 第2行第2列有一個2
0 1 0 0                     3 2 1   // 第3行第2列有一個1

試編程讀入一稀疏矩陣,轉換成簡記形式,並輸出。

輸入格式

輸入的第一行包含兩個整數 \(n,m(1 \le n \le 100)\),分別表示矩陣的行數和列數。
接下來 \(n\) 行,每行包含 \(m\) 個整數,用於表示二維數組中的每個元素(每個元素均為 \(1000\) 以內的正整數)。

輸出格式

輸出若干行,每行包含 \(3\) 個整數,以空格分隔,分別表示行號、列號和該非零元素的值。
請按照行號從小到大,行號相同的列號從小到大輸出這些數據。

樣例輸入

3 4
0 0 0 5
0 2 0 0
0 1 0 0

樣例輸出

1 4 5
2 2 2
3 2 1

問題分析

本題中需要解決的主要問題是查找非零元素並記憶位置。將原始矩陣存於數組 \(a\)。轉換後的矩陣存於數組 \(b\),當然 \(b\) 數組的行數可以控制在一個可控範圍內。
我們可以開一個變數 \(k\),一開始 \(k=0\),然後我們去遍歷每一行每一列。
如果第 \(i\) 行第 \(j\) 列的元素 \(a[i][j] \ne 0\),則執行如下操作:

k ++;
b[k][0] = i;
b[k][1] = j;
b[k][2] = a[i][j];

這樣,最終我們可以的數據將會保存在 \(b\) 數組中坐標從 \(1\)\(k\) 範圍內。

示例程式碼:

#include <bits/stdc++.h>
using namespace std;
int n, m, a[101][101], b[10010][3], k;
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            cin >> a[i][j];
            if (a[i][j]) {  // 輸入的同時就進行判斷
                k ++;
                b[k][0] = i;    // 標記行號
                b[k][1] = j;    // 標記列號
                b[k][2] = a[i][j];  // 標記數值
            }
        }
    }
    for (int i = 1; i <= k; i ++)
        cout << b[i][0] << " " << b[i][1] << " " << b[i][2] << endl;
    return 0;
}