Java基礎——數組
數組是一個語言中的基本要素,它能夠用來儲存和管理多個變數。例如,如果要統計三個學生的成績,可以手動的定義三個變數 a、b、c,如果要輸出這三個變數的值,也可以寫三個輸出語句。但是,如果要管理一個年級所有學生的成績,此時,可能有上百個學生。如果為每個學生都手動定義一個變數的話,則程式中會有上百個變數。並且,如果要 輸出所有學生的成績,就會有上百個輸出語句。很顯然,這樣的代碼是非常複雜和繁瑣的。
因此,我們就需要有一個辦法,能夠比較方便的管理多個資料。在這種情況下,我們就應該用到數組。 一、數組的基本操作
數組:一次性定義多個同類型的變數。
數組空間在記憶體中必定是連續的。
1,建立數組
int []a 或int a[] 表示定義一個int類型的一維陣列變數a
a=new int[3]; 表示分配了一個長度為3個int的記憶體空間
int[]a=new int[3]; 也可以兩部寫在一塊,表示定義一個int類型的一維數組同時分配長度為3個int的記憶體空間
2,下標
定義一個數組,就是一次性定義多個同類型的變數。為數組分配完空間之後,就可以使用數組了。使用數組的時候,應當用下標來表示數組元素。例如,上面分配了長度為3個int 類型的變數,這3個int 變數分別可以用:a[0]、a[1]、a[2]來表示。
即如果分配了一個長度為 n 的數組,則數組的下標範圍為 0~n-1。
a[0] = 10; //對數組元素進行賦值
a[1] = 20;
a[2] = 30;
3,遍曆數組
遍曆數組:按照一定順序,把每個元素都訪問一遍,不會遺漏,不會重複
範例程式碼:
package p5;public class TestArray{public static void main(String [] args){int[]a;//數組的定義 int []a; int a [];a=new int[3];//初始設定變數a,為數組分配空間,定義數組的長度a[0]=1;a[1]=2;a[2]=3;//數組的賦值for(int i=0;i<3;i++){//遍曆數組System.out.println(a[i]);}}}
運行結果:
4,數組的初始化
數組元素在沒有賦值的情況下可以使用,數組元素有特定的預設值
byte、short、int、long 這四種整數類型,預設值為 0
float 和 double 這兩種小數類型,預設值為 0.0
boolean 預設值為 false
char 預設值也為 0
注意,char 類型的 0 不是指的字元‘0’,而是指的編碼為 0。
對於物件類型的數組來說,預設值為 null。
顯示初始化
第一種形式如下:
int[] a = {10, 20, 30};
特點是,只能在定義陣列變數的同時使用。
第二種文法形式如下:
int[] a = new int[]{10, 20, 30};
注意,這種文法下,new 關鍵字後面的方括弧中沒有數字,也就是說,顯式初始化時不能規定數組長度,數組長度由後面的元素個數決定。
package p5;public class TestArray{public static void main(String [] args){int[]a;//數組的定義 int []a; int a [];a=new int[3];//初始設定變數a,為數組分配空間,定義數組的長度a[0]=1;a[1]=2;a[2]=3;//數組的賦值/*int[]a={1,2,3};//數組的顯示初始化,數組長度有括弧內元素個數決定//int []a=new int [](1,2,3);//int []a=new int [3](1,2,3); error!!!*/for(int i=0;i<3;i++){//遍曆數組System.out.println(a[i]);}}}
二、數組在記憶體中的表示
Java 數組在記憶體中的表示情況。看下面兩行代碼
int[] a;
a = new int[3];
我們結合代碼,分析一下數組在記憶體中的表示。
第一行,定義了一個陣列變數 a,此時沒有分配連續的記憶體空間。
第二行,首先執行了 new int[3],這句代碼分配了一個段連續的記憶體空間,總共能夠放 入 3 個 int,因此是 12 個位元組。這 12 個位元組每個位元組都有自己的一個記憶體位址,其中,12 個位元組中的第一個位元組,它的地址被稱之為這塊記憶體的“首地址”。假設首地址為 1a2b。第三步,執行完了 new int[3]之後,進行了賦值。究竟是把什麼賦值給了變數 a 呢。注 意,賦值賦的是記憶體的首地址。也就是說,陣列變數儲存的是數組中的首地址 1a2b。如下圖所示
三、二維數組 1,二維數組的基本操作
二維數組以及多維陣列:數組的數組。
比如說,我們日常生活中的抽屜,我們可以認為抽屜就是用來存放多個物品的,因此抽屜就是一個物品的數組。而一個柜子中,可以存放多個抽屜,因此我們可以理解為,柜子就是抽屜組成的數組。因此,柜子就可以理解為是“數組的數組”,也就是:柜子的元素是抽屜,而抽屜本身又是一個數組。
Ⅰ,建立二維數組
int[][] a; 或者 int[] a[]; 或者 int a[][];
定義二維陣列變數的時候,同樣沒有分配數組空間。
a = new int[3][4];
為二維數組分配記憶體空間,分配一個三行四列的二維數組
我們可以這 麼來看:我們分配的這個二維數組就相當於一個柜子,這個柜子有三層,每層放一個抽屜。這個抽屜裡面分成了四個格子,每個格子又能放一個元素。由於二維數組是“數組的 數組”,因此,二維數組的“行”,指的是這個二維數組中,包含幾個元素。由於二維數組 的元素是一維數組,因此,“行”也就是二維數組中包含幾個一維數組。而列,則指的是, 二維數組中的每一個一維數組,各自都包含幾個元素。
a[0][2]
表示第 0 行第 2 列的元素
int [][]a={{1,2,3}{5,6,7}{8,9,10}{11,12,13}};
二維數組的顯示初始化
Ⅱ,遍曆二維數組
遍曆二維數組時,要獲得行和列兩個數值。
首先,二 維數組同樣有 a.length 這樣的變數,而使用 a.length 獲得的長度,是二維數組元素的個數, 也就是行的數目,也可以理解成:柜子裡抽屜的個數。而列的數目,就相當於是每一個一 1a2b a … … 1a2b 7 維數組的長度,也可以理解為,是每一個抽屜的大小。對於第 i 個抽屜,我們可以使用 a[i].length 來獲得它的長度。
範例程式碼:
package p5;public class TestArray2{public static void main(String [] args){
//int [][]a=new int[4][3];//二維陣列變數的定義,並為二維數組分配記憶體空間,
//分配一個三行四列的二維數組// int [][]a=new int [][3];//error!!!int [][]a={{1,2,3},{5,6,7},{8,9,10},{11,12,13}};//二維數組的顯示初始化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();}}}
運行結果:
2,二維數組的記憶體表示
對於 a 數組來說,它還是一個一維數組,這個一維數組的長度為 3,也就 是說,a 數組有三個元素。而 a[0],a[1],a[2]又各自記錄了一個一維數組的地址。因此我們把 a 數組稱為“一維數組的一維數組”,也就是二維數組。
3,不規則數組
除了普通的二維數組之外,Java 還支援不規則數組。舉例來說,如果一個柜子有三個 抽屜,這個三個抽屜中並不一定每個抽屜都具有一樣的大小,完全有可能第三個抽屜更 大,元素更多,而第一個抽屜相對就比較小。
int[][] a; //定義陣列變數
a = new int[3][]; //先確定第一個維度,表明柜子裡有三個抽屜 a = new int[][3]; //error!
a[0] = new int[3]; //上層的抽屜有三個元素
a[1] = new int[4]; //下一層有四個元素
a[2] = new int[5]; //最底層有五個元素
四,數組的常見演算法 1,數組的擴容
首先,數組空間一旦分配完成之後,長度就不能改變了。因此,我們不能夠直接在原 有數組的空間後面增加新的記憶體空間。我們可以採用以下方式,來增加數組的長度:
①、分配一個新的數組,新數組的長度比原有數組要大(比如長度是原有數組的兩倍)
②、把原有數組中的資料,複製到新數組中。
package p5;import java.util.Arrays;public class TestArrayExpand{public static void main(String []args){int []a={1,2,3,4};//定義數組a,並顯示初始化aint []b=new int[8];//定義數組b,並為b分配記憶體空間,a=expand(a);}public static int[] expand(int[]a){//擴充方法1int []b=new int[a.length*2];for(int i=0;i<a.length;i++){b[i]=a[i];}return b;}public static int []expand1(int []a){//擴充方法2int []b=new int [a.length*2];System.arraycopy(a,0,b,0,a.length);return b;}public static int []expand2(int []a){//擴充方法3return Arrays.copyOf(a,a.length*2);}}
2,冒泡排序
在排序的過程中,相鄰元素不停進行比 較和交換。在交換的過程中,大的元素沉向數組的末尾,小的元素走向數組的開頭;這就好像在水裡面:重的東西往下沉,而輕的東西往上浮起來。正因為這種排序方式很像水裡 的氣泡往上浮的過程,因此,這種排序方式被稱為冒泡排序。
接下來,我們來寫冒泡排序的代碼。如果有五個元素,則需要進行 4 次迴圈,也就是 說,如果數組的長度是 a.length 的話,則需要進行 a.length-1 次迴圈。因此,外層迴圈如下:
for(int i = 0; i<a.length-1; i++){…}
內層迴圈稍有點複雜。我們讓內層迴圈的迴圈變數為 j,則每次進行比較的時候,比較 的都是 a[j]和 a[j+1]這兩個元素。那麼 j的迴圈條件怎麼寫呢。
第 1 次迴圈,i 的值為 0,因為要排到最後一個,因此 j+1 最大值為 a.length,j 的最大值為 a.length-1;
第 2 次迴圈,i的值為 1,j+1 的最大值為 a.length-1,j的最大值為 a.length-2;
第 3 次迴圈,i的值為 2,j+1 的最大值為 a.length-2,j的最大值為 a.length-3;
由上面,我們可知,每次迴圈 j+1 的最大值,都是 a.length-i;而 j 的最大值,就是 a.length-i-1。 因此,內層迴圈條件如下:
for(int i = 0; i<a.length-1; i++){for(int j = 0; j<a.length–i-1; j++){比較 a[j]和 a[j+1], 如果 a[j]比 a[j+1]大,則交換兩個元素的值 13}}
進一步細化,代碼為
for(int i = 0; i<a.length-1; i++){ for(int j = 0; j<a.length–i-1; j++){ if(a[j] > a[j+1]){ 則交換 a[j]和 a[j+1]的值 } } }
如何交換兩個變數的值呢。假設有兩個變數 a = 5;b=4;要交換兩個 a 和 b 的值,應該怎麼做呢。
如果直接執行 a = b 的話,則 a 的值 5 就會被 b 的值覆蓋。這樣,a 有了 b 的值,但是 b 卻無法獲得 a 變數原來的值了。因此,為了交換兩個變數的值,需要第三個變數參與。
首先,定義一個新變數 t; 然後,把 a 的值賦值給 t:t = a;
接下來,把 b 的值賦值給 a: a=b。這樣會覆蓋 a 原有的值,但是沒關係,a 原有的值 已經被儲存在 t 變數中了。
再接下來,把在 t 變數中儲存的原有的 a 變數的值,賦值給 b。
範例程式碼:
package p5;public class TestArraySort{public static void main(String[]args){int []data={5,4,2,1,3};//定義一個一維數組,並顯示初始化數組int n=data.length;//定義變數n為數組長度,便於後面使用數組長度for(int i=1;i<n;i++){//冒泡排序必定是n-1次,i表示第幾次冒泡排序for(int j=0;j<(n-i);j++){//歸納總結,從0開始data[j]與data[j+1]比較,比較n-i次if(data[j]>data[j+1]){int t=data[j];data[j]=data[j+1];data[j+1]=t;//data[j]與data[j+1]交換位置}}}for(int i=0;i<data.length;i++){System.out.print(data[i]+" ");//遍曆輸出data[i]}System.out.println();//換行 }} 運行結果:
3,選擇排序
選擇排序是一種簡單直觀的排序演算法。它的工作原理是每一次從待排序的資料元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的資料元素排完。選擇排序是不穩定的排序方法(比如序列[5, 5, 3]第一次就將第一個[5]與[3]交換,導致第一個5挪動到第二個5後面)
package p5;public class TestArraySort{public static void main(String[]args){int []data={5,4,2,1,3};//定義一個一維數組,並顯示初始化數組int n=data.length;//定義變數n為數組長度,便於後面使用數組長度for(int i=0;i<(n-1);i++){//選擇排序for(int j=i+1;j<n;j++){if(data[i]>data[j]){int t=data[i];data[i]=data[j];data[j]=t;}}}for(int i=0;i<data.length;i++){System.out.print(data[i]+" ");//遍曆輸出data[i]}System.out.println();//換行 }}