多維陣列
Arvin Liu @ C-Sprout 2021
10sec version
- 開一個空間為10 * 20的二維陣列
- 開一個空間為10 * 20 * 30 的三維陣列
- 用一個三維陣列的值,如讓第0個二維陣列裡的第2個一維陣列裡面的第5個值等於10
- 總之二維陣列就是一維陣列的一維陣列,三維陣列就是一維陣列的二維陣列(?)
int ary[10][20];
int ary[10][20][30];
ary[0][2][5] = 10;
如果覺得OK就去挑戰吧!
二維陣列?
就是陣列的陣列!
credit to leyna & 蔡銘軒 aka 軒爺/軒神
Problem: 需要100個放學生成績的空間。
宣告空間: int scores[100];
使用空間: scores[0] = 80; ...; scores[99] = 77;
最後空間可能就會變成 ...
一維陣列的例子?
neoj294 - 我愛零分
一排分數
0 | 1 | 2 | 1 | 0 |
---|
字串(一堆字元)
'H' | 'e' | 'l' | 'l' | 'o' |
---|
credit to 台大資工b07 程式電神人生勝利組 Joe Tsai 蔡銘軒軒哥
怎會用到二維陣列?
格子狀地圖 ((X,Y)放了甚麼)
很多個一維數據
關係圖 (A,B)=1 表示A喜歡B
A<->B, C<->D C->E
X | ♥ | - | - | - |
---|---|---|---|---|
♥ | X | - | - | - |
- | - | X | ♥ | ♥ |
- | - | ♥ | X | - |
- | - | - | - | X |
Rethink: Array
我們要將int scores 複製100份(?)
宣告: (((((int scores))))) [100];
那如果我們要將int ary[100]複製30份(?)
宣告: (((((int ary[100]))))) [30];
所以要開一個int型態的table變數複製30&30份
int table[30][30];
How to 二維陣列?
Usage
ary[0][0] | ary[0][1] | ary[0][2] | ary[0][3] | ary[0][4] |
---|---|---|---|---|
ary[1][0] | ary[1][1] | ary[1][2] | ary[1][3] | ary[1][4] |
ary[2][0] | ary[2][1] | ary[2][2] | ary[2][3] | ary[2][4] |
ary[3][0] | ary[3][1] | ary[3][2] | ary[3][3] | ary[3][4] |
ary[4][0] | ary[4][1] | ary[4][2] | ary[4][3] | ary[4][4] |
int ary[5][5];
宣告
//做出一個5x5的空間
使用
ary[i][j];
//使用第i個陣列裡面的第j個值
ary[0]
ary[1]
ary[2]
ary[3]
ary[4]
Example
? | 1 | ? | ? | ? |
---|---|---|---|---|
? | ? | 2 | ? | ? |
? | ? | ? | 3 | ? |
? | ? | ? | ? | 4 |
? | ? | ? | ? | ? |
int ary[5][5];
ary[0][1] = 1;
ary[1][2] = 2;
ary[2][3] = 3;
ary[3][4] = 4;
code
ary的長相
? : 不可預期的數字 (因為沒有初始化QQ)
Recap: 一維陣列的初始化
Initialization - 初始化1
0 | 0 | 0 | 0 | 0 |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
int ary[5][5]={0};
全部初始化成0
int ary[5][5]={};
其實可以連0都不要寫。
(但是有些IDE會出錯,ㄨㄚˊ )
code
ary的長相
Initialization - 初始化2
1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|
6 | 7 | 8 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
int ary[5][5] = \
{
1, 2, 3, 4,
5, 6, 7, 8
};
code
ary的長相
前八個元素是1~8,
(會自己換行!)
其他都是0
Initialization - 初始化3
1 | 2 | 3 | 0 | 0 |
---|---|---|---|---|
4 | 5 | 6 | 0 | 0 |
7 | 8 | 9 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
int ary[5][5] = \
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
code
ary的長相
左上角3x3個元素變成是1~9,
(利用{}指定換行!)
其他都是0
Initialization - 初始化X
1 | 0 | 0 | 0 | 0 |
---|---|---|---|---|
0 | 1 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
int ary[5][5] = \
{
{1},
{0, 1},
{[2] = 1},
};
code
ary的長相
有些神奇的compiler支援直接指定某個位置要甚麼值。
sorry, unimplemented: non-trivial designated initializers not supported
但是很多時候都不支援QQ,你會拿到下面的error。 (但neoj支援)
Recap: 多重迴圈
credit to leyna & 蔡銘軒 aka 軒爺/軒神
用for+cin指定陣列元素
int ary[10], n=10;
for(int i=0; i<n; i++){
cin >> ary[i];
}
int ary[10][10], n=10, m=10;
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
cin >> ary[i][j];
}
}
陣列不可以做的事情:(
不管是不是多維;(
X_X 多個值只能初始化給
int ary[3]={0};
// 做點事情hehe
ary[0] = 1;
ary[1] = 2;
ary[3] = 3;
for(int x : ary)
cout << x << " ";
int ary[3]={0};
// 做點事情hehe
ary = {1, 2, 3};
for(int x : ary)
cout << x << " ";
只能一個一個給,不能直接用{}給。
X_X 陣列不能直接 =,==
#include <cstring>
...
int A[3]={0};
int B[3]={1, 2, 3};
// 做點事情hehe
memcpy(A, B, sizeof(B));
for(int x : A)
cout << x << " ";
int A[3]={0};
int B[3]={1, 2, 3};
// 做點事情hehe
A = B;
for(int x : A)
cout << x << " ";
可以用memcpy複製陣列的值 (或就用for),
但是不能直接讓兩個陣列 =
但是要include cstring
(小小補充) for-each
int A[3]={1, 2, 3};
for(int x : A)
cout << x << " ";
int A[3]={1, 2, 3};
for(int i=0; i<3; i++){
x = A[i];
cout << x << " ";
}
左右是等價的code。
用:的方法稱作for-each,在C++11之後可以使用。
(陣列有偷偷存他到底多大,所以foreach知道跑到哪停)
Quick Review
Quick Review
- 開一個空間為10 * 20的二維陣列
- 開一個空間為10 * 20,初始化為0。
- 用一個二維陣列的值,如讓第0個一維陣列裡的第2個值等於10
- 要開很大的陣列去全域變數開!
(就是開在include的下面)
int ary[10][20];
int ary[10][20]={0};
ary[0][2] = 10;
Exercise!
踩地雷
踩地雷(?)
Problem Description
0 | 0 | 1 |
---|---|---|
1 | 0 | 1 |
1 | 0 | 1 |
1 | 3 | 1 |
---|---|---|
1 | 5 | 3 |
1 | 4 | 1 |
?
?
?
?
?
雙層迴圈
How 2 solve the edge?
Problem Description
Edge Problem
0 | 0 | 0 | 0 | 0 |
---|---|---|---|---|
0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 0 | 0 | 0 | 0 |
1 | 3 | 1 |
---|---|---|
1 | 5 | 3 |
1 | 4 | 1 |
Solution
#include <iostream>
using namespace std;
int main(){
int n, m, cnt[102][102]={0};
// Input
cin >> n >> m;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin >> cnt[i][j];
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
// Calculate
int mine = -cnt[i][j];
for(int x=i-1; x<=i+1; x++)
for(int y=j-1; y<=j+1; y++)
mine += cnt[x][y];
cout << mine << " \n"[j==m];
}
}
return 0;
}
多維陣列?
就是陣列的陣列!
那甚麼時候要用多維陣列呢?
影片: (時間, RGBA, X軸, Y軸)
圖片: (RGBA, X軸, Y軸)
3D場景 (X軸, Y軸, Z軸)
怎麼使用多維陣列呢?
開10 * 20 * 30 的三維陣列,給前2x2x2的方塊為1
開10 * 20 的二維陣列,
給前2x2的方塊為1
int ary[10][20]=\
{
{1, 1},
{1, 1}
};
int ary[10][20][30]=\
{
{
{1, 1},
{1, 1}
},{
{1, 1},
{1, 1}
},
};
使用1-2的值
使用1-2-3的值
cout << ary[1][2];
cout << ary[1][2][3];
陣列不可以做的事情:(
[好大][好大]的陣列
#include <iostream>
int main(){
char T[10][10]={
"Kon",
"Ban",
"DODODO!"};
for(int i=0; i<3; i++)
puts(T[i]);
return 0;
}
#include <iostream>
int main(){
char T[10000][10000]={
"Kon",
"Ban",
"DODODO!"};
for(int i=0; i<3; i++)
puts(T[i]);
return 0;
}
看起來好像沒有差?
Kon
Ban
DODODO!
Segmentation fault
(記憶體區段錯誤)
[好大][好大]的陣列
#include <iostream>
int main(){
char T[10000][10000]={
"Kon",
"Ban",
"DODODO!"};
for(int i=0; i<3; i++)
puts(T[i]);
return 0;
}
#include <iostream>
char T[10000][10000]={
"Kon",
"Ban",
"DODODO!"};
int main(){
for(int i=0; i<3; i++)
puts(T[i]);
return 0;
}
開在全域一切OK!
Segmentation fault
(記憶體區段錯誤)
Kon
Ban
DODODO!
開大概10^6的空間就建議往外開,
但是如果開太大(10^10)可能會吃CE QQ
真的真的很大的陣列
#include <iostream>
char T[1000000][1000000]={
"Kon",
"Ban",
"DODODO!"};
int main(){
for(int i=0; i<3; i++)
puts(T[i]);
return 0;
}
error: size of array 'T' is too large
char T[1000000][1000000]={
^
你該想想你到底出了甚麼問題了..
超出陣列範圍?
好像沒你想像中的簡單...
小小的範例
#include <iostream>
using namespace std;
int main(){
int A[3][3] = \
{1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int i: {0, 1, 2}){
for (int j : {0, 1, 2})
cout << A[i][j] << " ";
cout << endl;
}
cout << A[0][0] << endl;
cout << A[1][3] << endl;
cout << A[3][4] << endl;
return 0;
}
1 2 3
4 5 6
7 8 9
1
7
22021
Code
Output
Uncontrollable
Uncontrollable?
超越! 二維陣列
你感覺好像...
ary[0][0] | ary[0][1] | ary[0][2] |
---|---|---|
ary[1][0] | ary[1][1] | ary[1][2] |
ary[2][0] | ary[2][1] | ary[2][2] |
你的記憶體是一條的(?)
不是
超越! 二維陣列
所以其實二維陣列...
ary[0][0] | ary[0][1] | ary[0][2] |
---|---|---|
ary[1][0] | ary[1][1] | ary[1][2] |
ary[2][0] | ary[2][1] | ary[2][2] |
ary[0][0] | ary[0][1] | ary[0][2] | ary[1][0] | ary[1][1] | ary[1][2] | ary[2][0] | ary[2][1] | ary[2][2] |
---|
就是一維陣列(?)
=ary[0][3]
=ary[0][4]
=ary[0][5]
=ary[0][6]
=ary[0][7]
=ary[0][8]
=ary[1][3]
=ary[1][4]
=ary[1][5]
1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|
6 | 7 | 8 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
int ary[5][5] = \
{
1, 2, 3, 4,
5, 6, 7, 8
};
code
ary的長相
前八個元素是1~8,
(會自己換行!)
其他都是0
超越! 二維陣列
所以這樣初始化是合理的!
不能全部都放生嗎Σ( ° △ °)
但多維陣列只能放生第一個大小參數。
int A[][] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
error: declaration of ‘A’ as multidimensional array
must have bounds for all dimensions except the first
一維陣列可以放生大小參數。
對啊為甚麼呢?
Challenge Problem!
Problem Description
從I進去貼著左牆走走到O為止,把路徑都踩成*後輸出
nd-array
By Arvin Liu
nd-array
- 1,360