---
title: 'Array靜態陣列'
disqus: kyleAlien
---
Array靜態陣列
===
## OverView of Content
如有引用參考請詳註出處,感謝 :smile_cat:
[TOC]
## Static Data Sturct
* 靜態陣列有稱為`密集串列`,它是一種`有序串列`的資料使用**連續記憶體空間**
* 配置是在編譯期間,所以必須事先宣告,容易有浪費記憶體空間的現象
> 優點 : 找查記憶體十分快速
> 缺點 : 對於拓展空間、插入資料很浪廢資源,需要移動大量資料
* 列為主 : C、C++、Java...等等 (以下**主要介紹**)
* 行為主 : Fortran 語言(暫不介紹)
陣列 Array
---
* 陣列宣告方式是以數學式的宣告方式,而呼叫時是以陣列的方式呼叫
```java=
// 數學式 1~5
int[5] a = {874, 22, -3, 99, 0};
// 陣列式 0~4
a[0] = 874;
a[1] = 22;
a[2] = -3;
a[3] = 99;
a[4] = 0;
// 陣列超出範圍
a[5] = ???;
// a[5] 超出範圍,無法確定其值 ! (C 可以超出, Java 不允許超出)
```
> 陣列是電腦儲存資料的方式是一維
> > 電腦儲存的 index 是從 0 開始
> > 數學儲存的 index 是從 1 開始
> 而**數學的二維表達方式是使用矩陣**,而電腦儲存二維的方式是透過一維的拓展
> 也就是說**實際電腦記憶體中無法以矩陣分是儲存,就以線性方是在電腦儲存,可視為一維矩陣的延伸處理**
> > 電腦儲存的 index 是從 (0,0) 開始
> > 數學儲存的 index 是從 (1,1) 開始
### 一維陣列
#### C/C++
```c=
typedef struct {
int a; // 4
short b; // 2
char c; // 1
} Data_T;
int main() {
Data_T dataArray[10] = {0};
"1: "
int array1[] = {0};
int array2[5];
int array3[5] = {0};
"2: "
printf("array1 size: %i\n", sizeof(array1)); // 4
printf("Data_T size: %i\n", sizeof(Data_T)); // 8
"3: "
printf("dataArray size: %i\n", sizeof(dataArray) / sizeof(Data_T)); //10
}
```
* 1: C/C++ 宣告方式,可以以 struct 型式宣告陣列,並且有三種模式
> 宣告一個,不固定長度的陣列-->初始化
> 宣告一個,固定長度的陣列-->不初始化
> 選告一個,固定長度的陣列-->初始化
* 2: 計算的大小
> 第一個: **未定義矩陣長度的陣列,長度預設是一個,也就是 4 byte**
>
> 第二個: 原本計算出的大小應該是 7 byte,但答案是 8 byte
> **struct 會依照目前內部最大的空間作為倍數,做==數據對齊==**
* 3: 計算 struct Arrays 的方法(詳細請看C是如何計算和使用 sizeof)
#### Java
```java=
class TestClass {
private String str;
TestClass(String str) {
this.str = str;
}
String getData() {
return str;
}
}
public class main {
public static void main(String []args) {
"1: "
int[] array1;
int []array2;
int array3[];
TestClass[] testClassArray = { new TestClass("kyle"),
new TestClass("Alien"),
new TestClass("Pan")
};
for(int i = 0; i < testClassArray.length; i++) {
"2: "System.out.println(testClassArray[i].getData());
}
"3: "System.out.println(testClassArray[3].getData());
}
}
```
* 1: Java 有三種宣告方式,可以以 class 類型宣告陣列
> 但 **Java 宣告陣列不需要提供陣列的大小,陣列的大小在初始化時自動決定**
* 2: index 是 0 ~ 2,可正常輸出
* 3: 當超出範圍時會拋出錯誤,ArrayIndexOutOfBoundsException
**--實作--**
> ![](https://i.imgur.com/H3Z5jlg.png)
#### (一維)記憶體位子運算
> int[10] a = {0}, a[0] addr is 0x0010, a[5] addr 為多少 ?
>
> Ans : 由於 **a[5] 是電腦陣列表達式,數學表達式是 a(5+1) 的地方,也就是 a5**
> // **以下計算使用數學式計算**
>
> 0x0010 + (6 - 1)(行) * 4(byte) = 0x0010 + 20
> 0x0010 + 0x0014
> 0x0024
### 二維陣列
#### C/C++
```c==
typedef struct {
int a; // 4
short b; // 2
char c; // 1
} Data_T;
int main() {
Data_T dataArray[10][5] = {0};
"1: "
int array1[][5] = {0};
int array2[5][5];
int array3[5][5] = {0};
"2: "
printf("array1 size: %i\n", sizeof(array1)); // 20
printf("array2 size: %i\n", sizeof(array2)); // 100
printf("Data_T size: %i\n", sizeof(Data_T)); // 8
printf("dataArray size: %i\n", sizeof(dataArray // 400
printf("dataArray size: %i\n", sizeof(dataArray) / sizeof(Data_T)); // 50
}
```
* 1: C/C++ 宣告方式,同上有三種方式
> **一維陣列可不必定義大小,但二維的陣列一定要定義大小(不然不知道何時換行)**
* 2: 計算的大小
> 未定義預設一維就是 1, 4(byte) * 1 * 5 = 20
> 定義預設一維就是 5, 4(byte) * 5 * 5 = 100
> struct array -> 8 (struct 大小, 單位 byte) * 10 * 5 = 400
#### Java
```java=
class TestClass {
private String str;
TestClass(String str) {
this.str = str;
}
String getData() {
return str;
}
}
public class main {
public static void main(String []args) {
"1: "
int[][] array1;
int [][]array2;
int array3[][];
TestClass[][] testClassArray = {
{new TestClass("kyle"), new TestClass("12")},
{new TestClass("Alien"), new TestClass("23")},
{new TestClass("Pan"), new TestClass("16")}
};
"2: "
System.out.println("one length: " + testClassArray.length);
System.out.println("second length: " + testClassArray[0].length);
for(int i = 0; i < testClassArray.length; i++) {
for(int j = 0; j < testClassArray[i].length; j++) {
System.out.print(testClassArray[i][j].getData() + " ");
}
System.out.println();
}
}
}
```
* 1: Java 有三種宣告方式,可以以 class 類型宣告陣列
> 但 **Java 宣告陣列不需要提供陣列的大小,一維、二維陣列的大小在初始化時自動決定**
* 2: 透過自動偵測可判斷一維、二維的長度
> **testClassArray.length 是指向外層(二圍)的長度**
> testClassArray[0].length 是指內層(一維)的長度
**--實作--**
> ![](https://i.imgur.com/WEobOTo.png)
#### (二維)記憶體位子運算
> int[10][5] a = {0}, a[0][0] addr is 0x0010, a[3][2] addr 為多少 ?
>
> Ans : 由於 **a[3][5] 是電腦陣列表達式,數學表達式是 a(3+1)(2+1) 的地方,也就是 a42(矩陣)**
> // **以下計算使用數學式計算**
>
> 0x0010 + ((4 - 1)(列) * 5(行) + (2 - 1)(行)) * 4(byte)= 0x0010 + (15 + 1) * 4
> 0x0010 + 0x0040
> 0x0050
### 三維陣列
#### C/C++
```c=
typedef struct {
int a; // 4
short b; // 2
char c; // 1
} Data_T;
int main() {
Data_T dataArray[10][5][2] = {0};
"1: "
int array1[][5][2] = {0};
int array2[5][5][2];
int array3[5][5][2] = {0};
"2: "
printf("array1 size: %i\n", sizeof(array1)); // 20 * 2
printf("array2 size: %i\n", sizeof(array2)); // 100 * 2
printf("Data_T size: %i\n", sizeof(Data_T)); // 8
printf("dataArray size: %i\n", sizeof(dataArray // 400 * 2
printf("dataArray size: %i\n", sizeof(dataArray) / sizeof(Data_T)); // 50 * 2
}
```
* 1: C/C++ 宣告方式,同上有三種方式
> **一維陣列可不必定義大小,但二維、三維的陣列一定要定義大小**
* 2: 計算的大小
> 未定義預設一維就是 1, 4(byte) * 1 * 5 * 2= 40
> 定義預設一維就是 5, 4(byte) * 1 * 5 * 2= 200
> struct = 8 * 10 * 5 * 2 = 800
#### Java
```java=
class TestClass {
private String str;
TestClass(String str) {
this.str = str;
}
String getData() {
return str;
}
}
public class main {
public static void main(String []args) {
"1: "
int[][][] array1;
int [][][]array2;
int array3[][][];
TestClass[][][] testClassArray =
{
{
{new TestClass("kyle"), new TestClass("12")},
{new TestClass("Alien"), new TestClass("23")},
{new TestClass("Pan"), new TestClass("16")}
},
{
{new TestClass("kyle"), new TestClass("150cm")},
{new TestClass("Alien"), new TestClass("170cm")},
{new TestClass("Pan"), new TestClass("165cm")}
},
};
System.out.println("one length: " + testClassArray.length);
System.out.println("second length: " + testClassArray[0].length);
System.out.println("third length: " + testClassArray[0][0].length);
for(int i = 0; i < testClassArray.length; i++) {
for(int j = 0; j < testClassArray[i].length; j++) {
for(int k = 0; k < testClassArray[i][j].length; k++) {
System.out.print(testClassArray[i][j][k].getData() + " ");
}
System.out.println("---");
}
System.out.println();
}
}
}
```
* 1: Java 有三種宣告方式,可以以 class 類型宣告陣列
> 但 **Java 宣告陣列不需要提供陣列的大小,一維、二維、三維陣列的大小在初始化時自動決定**
* 2: 透過自動偵測可判斷一維、二維、三維的長度
> **testClassArray.length 是指向最外面一層(三圍)的長度**
> testClassArray[0].length 是指第二層(二維)的長度
> testClassArray[0][0].length 是指最內層(一維)的長度
**--實作--**
> ![](https://i.imgur.com/8RTTx4j.png)
#### (三維)記憶體位子運算
> int[10][5][10] a = {0}, a[0][0][0] addr is 0x0010, a[3][2][7] addr 為多少 ?
>
> Ans : 由於 **a[3][5][8] 是電腦陣列表達式,數學表達式是 a(3+1)(2+1)(8+1) 的地方,也就是 a429(矩陣)**
> // **以下計算使用數學式計算**
>
> 0x0010 + ((4 - 1)(列) * 5(行) * 10(高)+ (2 - 1)(行) * 10(高) + (9 - 1)(高)) * 4(byte)= 0x0010 + (150 + 10 + 8) * 4
> 0x0010 + 0x02A0
> 0x02B0
>
矩陣
---
* 矩陣是數學表達式,所以下方的**公式皆是以數學式表達,公式目的是為了轉換成電腦中的陣列**
### 矩陣相加
> 相加矩陣的**行列必須相等**
```java=
public class StartCoding {
public static boolean checkSize(int [][]a, int [][]b) {
boolean check = false;
int aLen = a.length;
int bLen = b.length;
if(aLen == bLen) {
if(a[0].length == b[0].length) {
check = true;
}
}
return check;
}
public static int[][] addMatrix(int [][]a, int [][]b) {
if(!checkSize(a, b)) {
return null;
}
int row = a.length;
int column = a[0].length;
int[][] c = new int[row][column];
for(int i = 0; i < row; i++) {
for(int j= 0; j < column; j++) {
c[i][j] = a[i][j] + b[i][j];
}
}
return c;
}
public static void main(String[] args) {
int [][]A = { // 3*3
{1,2,3},
{4,5,6},
{7,8,9}
};
int [][]B = { // 3*3
{1,1,1},
{2,2,2},
{3,3,3}
};
int[][] Result = addMatrix(A, B);
if(Result != null) {
System.out.println("Result: ");
for(int i = 0; i < Result.length; i++) {
for(int j = 0; j < Result[i].length; j++) {
System.out.print(Result[i][j] + " ");
}
System.out.println();
}
}
}
}
```
**--實作--**
> ![](https://i.imgur.com/fRlWhqE.png)
### 矩陣相乘
* 矩陣相乘算式
> 以 (3\*2) * (2\*4) = (3\*4) 的矩陣
> \[{1,1}, {2,2}, {3,3}] \* \[{4,4,4,4}, {1,2,3,4}]
>
> \[
> {(1\*4 + 1\*1), (1\*4 + 1\*2), (1\*4 + 1\*3), (1\*4 + 1\*4)},
> {(2\*4 + 2\*1), (2\*4 + 2\*2), (2\*4 + 2\*3), (2\*4 + 2\*4)},
> {(3\*4 + 3\*1), (3\*4 + 3\*2), (3\*4 + 3\*3), (3\*4 + 3\*4)},
> ]
>
> 結果: 3\*4 的矩陣
> \[5, 6, 7, 8
> 10, 12, 14, 16
> 15, 18, 21, 24]
```java=
public class StartCoding {
public static boolean checkSize(int [][]a, int [][]b) {
boolean check = false;
int aLen = a[0].length;
int bLen = b.length;
if(aLen == bLen) {
check = true; // check inner
}
return check;
}
public static int[][] multiplyMatrix(int [][]a, int [][]b) {
if(!checkSize(a, b)) {
return null;
}
int row = a.length; // 3
int column = b[0].length; // 4
int work = b.length; // 2
int[][] c = new int[row][column];
for(int i = 0; i < row; i++) { // 0 ~ 2
for(int j = 0; j < column; j++) {// 0 ~ 3
int temp = 0;
for(int k = 0; k < work; k++) { // k is Specify work index 0 ~ 1
temp = temp + (a[i][k] * b[k][j]);
}
c[i][j] = temp;
}
}
return c;
}
public static void main(String[] args) {
int [][]A = { // 3*2
{1,1},
{2,2},
{3,3},
};
int [][]B = { // 2*4
{4,4,4,4},
{1,2,3,4},
};
int[][] Result = multiplyMatrix(A, B);
if(Result != null) {
System.out.println("Result: ");
for(int i = 0; i < Result.length; i++) {
for(int j = 0; j < Result[i].length; j++) {
System.out.print(Result[i][j] + " ");
}
System.out.println();
}
} else {
System.out.println("Matrix format Err");
}
}
}
```
**--實作--**
> ![](https://i.imgur.com/0kM2s4S.png)
### 轉置矩陣
* 斜對角轉置矩陣,旋轉一個正方形矩陣,**對換斜對角的值**
```java=
public class StartCoding {
public static boolean checkSize(int [][]a) {
boolean check = false;
int aLen = a.length;
int bLen = a[0].length;
if(aLen == bLen) {
check = true; // check row == column
}
return check;
}
public static int[][] turnMatrix(int [][]a) {
if(!checkSize(a)) {
return null;
}
int row = a.length;
int column = a[0].length;
int [][]c = new int[row][column]; // create target/result array
for(int i = 0; i < row; i++) {
for(int j = 0; j < column; j++) {
c[i][j] = a[j][i];
}
}
return c;
}
public static void main(String[] args) {
int [][]A = { // 3*3
{1,2,3},
{4,5,6},
{7,8,9},
};
int[][] Result = turnMatrix(A);
if(Result != null) {
System.out.println("Result: ");
for(int i = 0; i < Result.length; i++) {
for(int j = 0; j < Result[i].length; j++) {
System.out.print(Result[i][j] + " ");
}
System.out.println();
}
} else {
System.out.println("Matrix format Err");
}
}
}
```
**--實作--**
> ![](https://i.imgur.com/MLVAzPz.png)
### 稀疏矩陣
* 一個矩陣中大部分都為 0 時,可把稀疏矩陣轉換成壓縮矩陣(兩個可以互相轉換)
* 壓縮是為了有效的利用空間,所以用了**三項式的資料結構**(i,j,Item-value)
> A(0,1) 該矩陣的列數
> A(0,2) 該矩陣的行數
> A(0,3) 該矩陣的非零項目的總數
| index | 1 | 2 | 3 |
| -------- | -------- | -------- | -------- |
| 0 | 6(總列數) | 6(總行數) | 8(總非零數) |
| 1 | 列 | 行 | 數值 |
| 2 | 列 | 行 | 數值 |
| 3 | 列 | 行 | 數值 |
```java=
public class StartCoding {
private static final int Trinomial = 3;
public static int[][] decompress(int [][]a) {
int row = a[0][0];
int colume = a[0][1];
int unZeroCount = a[0][2];
int temp = 1;
int [][]c = new int[row][colume];
for(int i = 0; i < row; i++) {
for(int j = 0; j < colume; j++) {
int saveRow = (a[temp][0] - 1);
int saveColume = (a[temp][1] - 1);
if(i == saveRow && j == saveColume) {
c[i][j] = a[temp][2];
temp = temp + 1 > unZeroCount ? temp : temp + 1;
}
}
}
return c;
}
public static int[][] compression(int [][]a) {
int unZeroCount = 0;
int row = a.length;
int colume = a[0].length;
for(int i = 0; i < row; i++) {
for(int j = 0; j < colume; j++) {
if(a[i][j] != 0) { // find not 0 value
unZeroCount++;
}
}
}
int [][] c = new int[unZeroCount + 1][Trinomial]; // +1 for one line is info
c[0][0] = row;
c[0][1] = colume;
c[0][2] = unZeroCount;
int temp = 1;
for(int i = 0; i < row; i++) {
for(int j = 0; j < colume; j++) {
if(a[i][j] != 0) {
c[temp][0] = i + 1;
c[temp][1] = j + 1;
c[temp++][2] = a[i][j];
}
}
}
return c;
}
private static void print(int[][] a) {
for(int i = 0; i < a.length; i++) {
for(int j = 0; j < a[i].length; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
int [][]A = { // 6*6
{ 25, 0, 0, 32, 0,-25},
{ 0, 33, 77, 0, 0, 0},
{ 0, 0, 0, 55, 0, 0},
{ 0, 0, 0, 0, 0, 0},
{101, 0, 0, 0, 0, 0},
{ 0, 0, 38, 0, 0, 0},
};
System.out.println("----------------- compression");
int [][] Result = compression(A);
print(Result);
System.out.println("----------------- decompression");
int [][] conveter = decompress(Result);
print(conveter);
}
}
```
**--實作--**
> ![](https://i.imgur.com/puF8kti.png)
### 三角矩陣
> 三角矩陣又分為,右上、左上、右下、左下三角矩陣,除了三角區域以外都是0元素
> 我們**可以把三角矩陣的==二維模式透過一維的陣列存取==**,目的為了壓縮矩陣大小,節省空間
> 透過**呼叫原矩陣座標在一維陣列中取出儲存值**
> **Item 總數公式 `n*(n+1)/2`** (正三角)
#### 右上三角
![](https://i.imgur.com/aOCK0lE.png)
* 找出向量座標 A2-3(i = 2, j = 3) 在一維陣列 B[index] 中的 index
* index = n*(i-1) - (i * (i-1))/2 + j
> n*(i-1) : 算出 A2-3 以上的面積
> (i * (i-1))/2 : 扣除矩陣中 0 的項目(0 不放入一維陣列中儲存)
> j : 加上位移的座標
```java=
public class StartCoding {
public static void main(String[] args) {
int [][]A = { // 4*4
{ 25, 1, 15, 32},
{ 0, 33, 77, -1},
{ 0, 0, -9, 55},
{ 0, 0, 0, 9}
};
CompressSize cs = new CompressSize(A);
for(int i = 0; i < A.length; i++) {
for(int j = 0; j < A[i].length; j++) {
int x = cs.getDataByMatrixIndex(i + 1, j + 1); // +1 is array type to matrix type
System.out.println(x);
}
}
System.out.println("---------");
System.out.println("A23 : " + cs.getDataByMatrixIndex(2, 3));
}
}
class CompressSize {
private int[] array;
private int size = 0;
public CompressSize(int [][]a) {
makeArray(a);
int index = 0;
for(int i = 0; i < a.length; i++) {
for(int j = 0; j < a[i].length; j++) {
if(a[i][j] != 0) {
array[index++] = a[i][j];
}
}
}
}
private void makeArray(int [][]a) {
size = a.length;
int s = (size * (size + 1)) /2;
array = new int[s];
}
public int getDataByMatrixIndex(int x, int y) {
int cache = size * (x-1);
int notZero = (x * (x-1)) / 2;
cache = cache - notZero + y;
return array[cache - 1]; // cache is matrix type, -1 for change to array type-=0
}
}
```
**--實作
> ![](https://i.imgur.com/rPQk92k.png)
#### 左下三角
![](https://i.imgur.com/ywBsqTf.png)
* **主要改變在 getDataByMatrixIndex 的算式**
* 找出向量座標 A32(i = 3, j = 2) 在一維陣列 B[index] 中的 index
* index = (i * (i-1))/2 + j
> (i * (i-1))/2 : **非 0 的項目**(0 不放入一維陣列中儲存)
> j : 加上位移的座標
```java=
public class StartCoding {
public static void main(String[] args) {
int [][]A = { // 4*4
{ 25, 0, 0, 0},
{ 1, 33, 0, 0},
{ 2, 10, -8, 0},
{ 3, 20, 50, 9}
};
CompressSize cs = new CompressSize(A);
for(int i = 0; i < A.length; i++) {
for(int j = 0; j < A[i].length; j++) {
int x = cs.getDataByMatrixIndex(i + 1, j + 1); // +1 is array type to matrix type
System.out.println(x);
}
}
System.out.println("---------");
System.out.println("A32 : " + cs.getDataByMatrixIndex(3, 2));
}
}
class CompressSize {
... 同上
public int getDataByMatrixIndex(int x, int y) {
int notZero = (x * (x-1)) / 2;
int cache = notZero + y;
return array[cache - 1]; // cache is matrix type, -1 for change to array type
}
}
```
**--實作
> ![](https://i.imgur.com/f6MV0EN.png)
#### 左上三角
![](https://i.imgur.com/yl1IEgr.png)
* **主要改變在 getDataByMatrixIndex 的算式**
```java=
// 主要在改變 getDataByMatrixIndex 的算式
```
#### 右下三角
![](https://i.imgur.com/IkXhKT0.png)
* **主要改變在 getDataByMatrixIndex 的算式**
```java=
// 主要在改變 getDataByMatrixIndex 的算式
```
## Appendix & FAQ
:::info
:::
###### tags: `資料結構`