文章目錄
- 什么是陣列
- 舉個例子,我現在要創建一個整形陣列
- 注意事項: 在 Java 中, 陣列中包含的變數必須是 相同型別
- 創建陣列
- 1.靜態初始化
- 基本語法
- 程式實體
- 既然創造出陣列,就必然有它存在的價值,那么陣列的好處是什么?
- 例
- 而且對陣列有一定了解的人,都知道**陣列的每個元素都有一個下標(從0開始)**,方便去尋找尋找元素.
- 圖1
- 注意事項: 靜態初始化的時候, 陣列元素個數和初始化資料的格式是一致的(依據初始化元素的數量,來決定陣列的大小)
- 2.動態初始化
- 基本語法
- 代碼實體
- 第三種創建陣列的方法
- 基本語法:
- 代碼實體
- 總結
- 陣列的使用
- 代碼實體1(獲取陣列的長度)
- 圖2
- 代碼實體2 (讀取陣列中某個元素)
- 圖3
- 代碼實體3(陣列越界問題)
- 圖4
- 續代碼3
- 圖 5
- 代碼實體4(改變陣列某元素的值)
- 圖6
- 注意事項
- 遍歷陣列
- 代碼實體1(for回圈 - 遍歷列印陣列元素)
- 圖7
- 代碼實體2(增加for回圈 - foreach - 圖 8)
- foreach 基本語法:
- 圖 8
- 圖9
- 那么 for 和 foreach 兩者有什么區別?
- 代碼實體3(借助Java的操作陣列的工具類 Arrays 圖10)
- 圖10
- 圖11
- 圖12
- 陣列作為方法的引數
- 首先我們需要搞懂幾樣東西
- 看代碼
- 圖13(這圖沒截好,下半部分少了東西,不過無傷大雅)
- 代碼實體
- 圖14
- 圖15
- 現在我們來嘗試用方法來遍歷列印陣列
- 代碼如下
- 圖16
- 圖17
- 實踐題
- 題目一
- 題目2
- 圖 18
- 圖19
- 圖解(圖20)
- 還有一個問題值得討論:一個參考 是否 能同時 指向 多個物件?
- 結論
- 另外注意
- 這時候,我們來講講前面文章留下來的問題(使用方法,來交換兩個變數的值)
- 圖21
- 陣列作為方法的回傳值
- 代碼示例: 寫一個方法, 將陣列中的每個元素都 * 2
- 先來寫沒有回傳值的(將原來的陣列元素都擴大2倍)
- 圖 22
- 圖23
- 現在我們來寫有回傳值的(不在原來的陣列上擴大2倍,保護原來的陣列不被破壞)
- 代碼入下
- 圖24
- 圖25
- 陣列練習
- 模擬實作 toString 函式
- 代碼如下
- 圖26
- 找陣列中的最大元素
- 圖27
- 查找陣列中指定元素(順序查找),回傳它的下標
- 查找陣列中指定元素(二分查找),回傳其下標
- 圖28
- 圖29
- 其實在Java中有一個工具,就是二分查找,意味這我們沒必要像上面一樣去寫一個二分查找的方法
- 寫法: Arrays.binarySearch(陣列名,想查找的元素)
- 代碼如下
- 圖30
- 圖31
- 圖32
- 二分查找對于有序數列的效率是非常高的,你想想取一個中間下標的值
- 圖33
- 檢查陣列的有序性(升序:從左往右,從小到大)
- 圖34
- 圖35
- 陣列排序(冒泡排序)
- 升序
- 圖36
- 圖37
- 經過上面的講解,至少你對冒泡有一定的了解,很遺憾,我想告訴你,我們辛辛苦苦做出的冒泡排序,在Java是有函式可以做到的(但并不意味我們剛才的努力都是白費,萬一面試官,讓你模擬實作一個冒泡排序呢?)對吧? 廢話不多說,我們來看看這哥函式是什么?
- Arrays.sort
- 圖38
- 圖39
- 我們在順便拓展一下 Arrays 的其它功能
- Arrays.fill
- 圖 40
- 圖41
- 圖42
- 根據圖 43,發現 Arrays,fill 的引數,還可以寫兩個
- 圖43
- 圖44
- 陣列逆序
- 圖45
- 陣列數字排列
- 圖46
- 陣列拷貝
- 拷貝方法1 回圈拷貝
- 代碼如下
- 圖47
- 圖48
- 方法2
- 圖 49
- 代碼如下
- 圖50
- 圖51
- 圖52
- 方法3
- 圖53
- 但是我們先來看第四種方法,為第三種方法做鋪墊
- Arrays.copyOfRange()
- 圖54
- 代碼如下
- 圖 55
- 好,現在我們來看看 第三方法
- 圖56
- 拓展
- 圖 57
- 方法 5 陣列克隆
- 基本語法:
- 圖58
- 在 一維陣列的最后我們在講一個概念, 深拷貝 和 前拷貝
- 圖 59
- 二維陣列
- 二維陣列的創建
- 基本語法1
- 基本語法2
- 基本語法3
- 跟一維陣列幾乎一樣,只要初始化了資料,你的[][]里就不能有數字的存在
- 代碼如下
- 二維陣列的列印
- 圖60
- 圖 61
- 圖 62
- 接著我們來對上面的程式(二維陣列的列印)進行改良
- 圖63
- 前面使用for回圈來列印陣列,這回我們foreach
- 圖64
- 還有一種輸出二維陣列的方法
- 圖65
- 接下來,我會讓你們見識到一種特別的二維陣列
- 代碼案例
- 圖66
- 再來舉個例子
- 圖67
- 圖68
- 圖69
- 圖70
- 哪有人可能會問,雖然寫法沒問題,但是程式運行會報錯,那么省略列的意義在哪?
- 代碼如下
- 圖71
- 圖72
- 本文結束,
什么是陣列
陣列本質上就是讓我們能 "批量" 創建相同型別的變數
也可以說是存盤一組相同資料型別的資料的集合
舉個例子,我現在要創建一個整形陣列
int[] array
int[] 就是相當于是一個型別(整形陣列型別),
而 array 就相當于 該型別的變數
總得來說 就是我創建一個變數,它的型別是整形陣列型別
再來看看這個 int a =10; a是變數,型別是int,且只能存盤一個值,
而 int[] array,array是變數,型別是int[],它能存盤一組相同型別的資料(能存盤型別相同的資料,個數不限,取決你想放多少個型別相同的資料)
例: int[] array ={1,2,3,4,5,6}
注意事項: 在 Java 中, 陣列中包含的變數必須是 相同型別
?
創建陣列
1.靜態初始化
基本語法
資料型別[] 陣列名稱 = { 初始化資料 };
程式實體
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array ={1,2,3,4,5,6};
//資料型別[]+陣列名稱 = { 初始化資料 }; 如果后面已將陣列初始化元素值了,其中[]里不能加任何數字,這是Java創建陣列時,靜態初始化的一個特點.
}
}
?
既然創造出陣列,就必然有它存在的價值,那么陣列的好處是什么?
如果我們沒有資料的支持,我們想要定義 6 個整形會變得巨繁瑣,反正我學了陣列,像例子這種呆頭呆腦的寫就沒用過了,
例
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int e = 5;
int f = 6;
}
}
?
而且對陣列有一定了解的人,都知道陣列的每個元素都有一個下標(從0開始),方便去尋找尋找元素.
而且是所有元素都存盤在一塊連續的空間上,所以從記憶體上看,所有元素都是緊鄰(圖1)</font>
圖1

注意事項: 靜態初始化的時候, 陣列元素個數和初始化資料的格式是一致的(依據初始化元素的數量,來決定陣列的大小)
?
2.動態初始化
基本語法
資料型別[] 陣列名稱 = new 資料型別 [] { 初始化資料 };
代碼實體
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = new int[]{1,2,3,4,5,6};//其表達意思與作用與第一種方法相同,就是創建一個陣列,并初始化資料
// 兩個[]中,都不能有數字的存在
// new 是java中的一個關鍵字,其作用是實體化一個物件
// 意味著 在Java 陣列其實是一個物件,物件具體是什么,后面再降
// (注意,并不是前面有new,陣列才是一個物件,而是陣列本來是就是一個物件)
//先這么認為,陣列就是一款網頁游戲,游戲沒打開之前,它只是一個圖示,而new的作用就是加載這游戲成為物體,就是運行起來,
}
}
?
第三種創建陣列的方法
基本語法:
型別[] 陣列名 = new 型別[元素個數];
就是第二種方法中,洗掉了初始化資料,前者的[]中是不能有數字的存在,后者的[]可以有具體的數字來表示陣列元素的個數
代碼實體
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = new int[6];
// 該寫法表達的意思是 現在有一個陣列,長度為6,注意陣列的元素,并沒有對其初始化,在Java中,默認6個元素都是0
// 等價于 int[] array={0,0,0,0,0,0},
}
}
?
總結
一套講解下來,你會發現在Java中 是這么來表達一個陣列:int[] array
其實陣列也可以寫成
int arr[] = {1, 2, 3};
和 C 語言一樣. 但是我們還是更推薦寫成 int[] arr 的形式. int和 [] 是一個整體.,因此,其實在Java中陣列的寫法更為準確,
但是不能像C語言一樣這樣寫 int array[10] = {0};
我們前面也看到了,在創建一個陣列時,[]里是不能有具體數字的存在,除了第三種方法,其它的,一律不行,
?
陣列的使用
代碼實體1(獲取陣列的長度)
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
// 注意在Java是沒有sizeof這種東西的,那么有人可能會問,在陣列元素個數未知的情況下,我們該如何獲得陣列元素個數?
// 方法 : 陣列名.length 這樣寫Java就會自動獲取陣列的長度(元素個數),
System.out.println(array.length);
}// 圖2
}
圖2

?
代碼實體2 (讀取陣列中某個元素)
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
// 下標從0開始,4的下標就是 3
// 訪問方法: 陣列名[下標]
System.out.println(array[3]);
}// 圖 3
}
圖3

?
代碼實體3(陣列越界問題)
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
// 下標從0開始遞增,也就是正數下標,不存在所謂的負數下標
System.out.println(array[-1]);// 我們將訪問元素的下標寫成負數,讓我們來看看效果如何,
}// 圖 4
}
圖4

?
續代碼3
還有一種情況:元素只有 5 個,下標最高為4,你卻要訪問第6個元素,也就是下標為 5 的元素
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
System.out.println(array[5]);// 現在我們將訪問元素的下標寫成5,讓我們來看看效果如何,
}// 圖 5
}
圖 5

?
代碼實體4(改變陣列某元素的值)
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
// 改變 元素3 的值,也就是改變陣列中下標為2的元素值
// 方法 陣列名[下標] = 新值;
array[2]=8;
System.out.println(array[2]);// 讓我們來看看效果如何,
}// 圖 6
}
圖6

?
注意事項
1. 使用 arr.length 能夠獲取到陣列的長度. . 這個操作為成員訪問運算子. 后面在面向物件中會經常用到.
2. 使用 [ ] 按下標取陣列元素. 需要注意, 下標從 0 開始計數
3. 使用 [ ] 操作既能讀取資料, 也能修改資料.
4. 下標訪問操作不能超出有效范圍 [0, length - 1] , 如果超出有效范圍, 會出現下標越界例外
?
遍歷陣列
代碼實體1(for回圈 - 遍歷列印陣列元素)
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
// println 是因為它自帶換行,輸出結果是豎著的,不好看,
// 所以我使用的是 print 列印不換行
}//圖 7
}
}
圖7

?
代碼實體2(增加for回圈 - foreach - 圖 8)
foreach 基本語法:
for(定義一個 與陣列元素型別 相同的變數 : 陣列名)
什么意思呢?
foreach(增加for回圈), 陣列名部分,表示的意思 遍歷訪問陣列的元素
將訪問的元素賦給 冒號前面 定義的 與陣列元素型別相同 的變數
我們只需要 將該變數每次得到的元素值,列印
就能做到不依靠元素下標,遍歷列印陣列所有元素
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
for (int x:array) {
System.out.print(x+" ");
}
}//圖9
}
圖 8

圖9

?
那么 for 和 foreach 兩者有什么區別?
最大的區別在于,for是可以拿到元素下標,而foreach拿不到元素下標
for回圈用到的地方很多,但是foreach呢?
當我們只需要元素的值時,就是使用foreach,
當我們還需要元素的下標時,就用for,
for-each 是 for 回圈的另外一種使用方式. 能夠更方便的完成對陣列的遍歷. 可以避免回圈條件和更新陳述句寫錯
?
代碼實體3(借助Java的操作陣列的工具類 Arrays 圖10)
toString 將當前的陣列元素,轉換成字串形式,并將其回傳(也可以說 將引數的陣列,以字串形式進行輸出)
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
String str = Arrays.toString(array);// 創建一個字串變數來接收它的回傳值
System.out.println(str);// 圖 11
// 因為 Arrays.toString 是有回傳值的,所以可以直接輸出
System.out.println(Arrays.toString(array));//圖12
}
}
圖10

圖11

圖12

?
陣列作為方法的引數
首先我們需要搞懂幾樣東西
看代碼
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array ={1,2,3,4,5};
int a = 10;
}
}
array 和 a 都是區域變數,在堆疊上開辟空間
那么問題來了,a的空間里存的是 10
而陣列后面的一大坨資料,放在哪里?
和 10 一樣放在堆疊上?
然而并不是,還記得前面說到 陣列是一個物件嗎?
物件是存放在 堆上的.
在這里我們就需要介紹一些東西,圖13
圖13(這圖沒截好,下半部分少了東西,不過無傷大雅)

參考很像指標,最大的區別就是不能對 參考 解參考,可以對指標解參考,因為在Java沒有傳址的概念的,其他功能類似,但時兩個東西,不是同一個東西,不能混淆在一起,
有個問題就誕生了,指標有空指標,那參考有空參考(參考里面存的地址是空的)嗎?
答案是有的,只不過跟C語言不同,C是大寫NULL,Java是小寫null
但是請注意,舉這個例子只是為了讓你理解參考是一個什么東西,順便區別兩者,
C的東西只是輔助你理解Java,盡量學Java的時候,拋開C,兩者(參考和指標)有很多不同地方,
代碼實體
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] array1 = null;
//當一個參考被賦予null,就代表這該參考不指向任何物件
// 既然該參考不指向任何物件,那么我這樣寫代碼會怎么樣?
System.out.println(array1.length);
// 求一個空參考所指向的物件的長度,但是空參考不會指向任何一個物件的
// 何來的長度?那么代碼運行的效果如何?
圖14,由圖可知該寫法是錯誤的,另外參考被指為null,堆上是不會分配記憶體給它的
// 意思是你都不創建任何物件,你還想拿我空間,瘋了?
System.out.println(array1[0]);
// 這個寫法毫無疑問也是錯的,沒物件,你怎么訪問物件里的東西?
來看看圖 15
}
}
圖14

圖15

?
現在我們來嘗試用方法來遍歷列印陣列
代碼如下
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
print(array);
}
public static void print(int[] array){
for (int x:array) {
System.out.print(x+" ");
}
System.out.println();// 換行
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
}// 效果見圖16
}//讓我們通過 圖17 來說明
圖16

圖17

舉個例子,你玩游戲DNF,有倉庫對吧,你會設密碼對吧?要不然被盜號,就算找回來,里面的東西也不見了,
只要別人知道你的密碼,他不就可以拿里面的東西了嗎?
按參考傳遞,就相當于你找朋友刷東西,把密碼告訴他,這樣他才能打開你的倉庫,在里面拿或者取 裝備和材料,不然他怎么刷的動?
?
實踐題
下面兩題先思考答案,再去看結果附圖,這樣你們才能對參考的理解進一步加深
下面兩題的輸出結果是什么?
題目一
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
func1(array);
System.out.println(Arrays.toString(array));// 圖 18
}
public static void func1(int[] array){
array = new int[]{11,2,13,4,51};
}
}
題目2
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
func2(array);
System.out.println(Arrays.toString(array));
}
public static void func2(int[] array){
array[0] = 99;
}
}//圖19
?
?
?
?
?
?
?
?
?
圖 18

圖19

##題目路2的兩個array等價于下面的程式 array 和 array2
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] array2 = array;
這代表 array2 這個參考 指向 參考array指向 的物件
array 和 array2 指向的是同一個物件
}
}
圖解(圖20)

?
還有一個問題值得討論:一個參考 是否 能同時 指向 多個物件?
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array1 = new int[]{1,2,3,4,5};
array1 = new int[10];
array1 = new int[2];
array1 = new int[4];
}
}
答案是不能,如果前面認真看了,就該知道此時的array1,存盤的地址,已經被改變(array是一個區域變數,意味著存的值是可以被改變的),現在存的是 new int[4] 的這個物件的地址, 而不是說,存幾個物件的地址,
結論
一個參考只能指向一個物件(一個參考只能保存一個物件的地址)
?
另外注意
寫了這么多,有沒有發現我們寫的參考,都是在堆疊上
那么 參考 就一定在堆疊上嗎?
答案是不一定的,因為一個變數在不在堆疊上,是你變數的性質決定的
如果你的參考是一個區域變數,那就一定在堆疊上
實體成員變數那就不一定了,(先告訴你們有這個概念,等后面講到成員變數時,再說)
區域變數的參考保存在堆疊上, new 出的物件保存在堆上.
堆的空間非常大, 堆疊的空間比較小.
因為 堆 是整個 JVM 共享一個,
而 堆疊 每個執行緒具有一份 (一個 Java 程式中可能存在多個堆疊)
?
這時候,我們來講講前面文章留下來的問題(使用方法,來交換兩個變數的值)
因為Java中是取不到堆疊上變數的地址的,也就意味不能傳址,所以無法按照C一樣去實作
但是今天我們學了陣列,我們用陣列的方式來解決問題
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
//int a = 10;
//int b = 20;
// 我們將其放在一個陣列里,進行交換
int[] array = {10,20};
swap(array);
System.out.println(Arrays.toString(array));
}
public static void swap(int[] array){
int tmp = array[0];
array[0] = array[1];
array[1] = tmp;
}
}// 圖21,這只是一種取巧的方式來進行交換,等到我講到類和物件的那個時候,會再講幾種方法
圖21

?
陣列作為方法的回傳值
代碼示例: 寫一個方法, 將陣列中的每個元素都 * 2
先來寫沒有回傳值的(將原來的陣列元素都擴大2倍)
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
func(array);
System.out.println(Arrays.toString(array));
}
public static void func(int[] array){
for (int i = 0; i < array.length; i++) {
array[i]=2*array[i];
}
}//圖22
}// 圖解(圖23)
圖 22

圖23

?
現在我們來寫有回傳值的(不在原來的陣列上擴大2倍,保護原來的陣列不被破壞)
代碼入下
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
int[] ret = func(array);//建立陣列型別(物件)變數來接收
System.out.println(Arrays.toString(ret));
System.out.println(Arrays.toString(array));
}
public static int[] func(int[] array){
int[] ret = new int[array.length];
for (int i = 0; i < array.length; i++) {
ret[i]=2*array[i];
}
return ret;//這里回傳是 新建物件(陣列),在堆上的地址
}//圖24
}// 圖解(圖25)
圖24

圖25

這樣的話就不會破壞原有陣列了.
另外由于陣列是參考型別, 回傳的時候只是將這個陣列的首地址回傳給函式呼叫者, 沒有拷貝陣列內容, 從而比較高效.
有的人可能會說,方法呼叫完的時候,不是會銷毀堆疊上的空間,我們這樣將地址帶回來,不會存在一些問題嗎?
請注意 new 的物件,都是存在堆上的,而不是堆疊上,這里的回傳的是將堆上物件的地址(注意回傳型別int[]),而不是區域變數ret,所以不會出現問題,
?
陣列練習
模擬實作 toString 函式
toString 將當前的陣列元素,轉換成字串形式,并將其回傳(也可以說 將引數的陣列,以字串形式進行輸出) 圖12
代碼如下
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
String str = myToString(array);
System.out.println(str);
}
public static String myToString(int[] array){
if(array == null){
return "null";// 判斷是否形參接收的地址,是否為空指標
}
String str = "[";
for (int i = 0; i < array.length; i++) {
str+=array[i];// 用了一開始拼接輸出方式,字串開頭后面用+拼接,使其成為一個字串
if(i< array.length-1){// array.length-1,因為最后一個元素不用加 ,號
str+=",";
}
}
str+="]";
return str;
}
}// 圖26
圖26

?
找陣列中的最大元素
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {12,8,1,2,10};
System.out.println(maxNum(array));
}
public static int maxNum(int[] array){
if(array==null){
return -1;// 假設 -1 意味著array存盤的是空指標
}
if(0 == array.length){
return -2;// 假設 -2 意味著 array 沒有元素(int[] array = {})
// 故 陣列長度為0(元素個數為0).
}
int max = array[0];
for (int i = 1; i < array.length; i++) {
if(max<array[i]){
max = array[i];
}
}
return max;
}// 圖 27
}
圖27

?
查找陣列中指定元素(順序查找),回傳它的下標
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,23,213,67,123};
System.out.println(find(array,23));
}
public static int find(int[] array,int y){
for (int i = 0; i < array.length; i++) {
if (array[i] == y){
return i;
}
}
return -1;// 表示沒找到,因為陣列的下標不可能存在負數
}
}

?
查找陣列中指定元素(二分查找),回傳其下標
針對有序陣列, 可以使用更高效的二分查找
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
System.out.println(find(array,4));
}
public static int find(int[] array,int y){
int right = array.length-1;// 右下標
int left = 0;// 左下標
int mid = 0;
while(right>=left){
mid=(right+left)/2;
if(array[mid]>y){
right--;
}
else if(array[mid]<y){
left++;
}else{
return mid;
}
}
return -1;//表示沒找到
}
}// 圖28
圖釋( 圖29)
圖28

圖29

?
其實在Java中有一個工具,就是二分查找,意味這我們沒必要像上面一樣去寫一個二分查找的方法
寫法: Arrays.binarySearch(陣列名,想查找的元素)
代碼如下
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
System.out.println(Arrays.binarySearch(array,2));// 圖30
// 如果找一個不存在的數呢?
System.out.println(Arrays.binarySearch(array,6));// 圖 31
// 有人會好奇,為什么是-6?
// 左鍵點擊 binarySearch,ctrl + 左鍵點擊
// 再點擊 binarySearch,ctrl + 左鍵點擊
你會看到 圖 32
// -(low+1),意思是最后low的位置下標+1,取負
// 因為我們要找的數,比有序陣列里所有元素都要大,所以最后low的位置應該最后一個元素的位置
// 也就是下標為 5 的位置,對其加一取負,所以輸出的值是-6
// 另外注意,下標是沒有負數的,別以為這-6 是一個元素的下標,不是的啊,
// 只是告訴你找不到,
// 下標不可能為負,你給我個負數,不是找不到是什么
}
}
圖30

圖31

圖32

?
二分查找對于有序數列的效率是非常高的,你想想取一個中間下標的值
不管你要找的數,是大于或者小于這個值,都意味著有一邊的資料直接pass,
圖33

?
檢查陣列的有序性(升序:從左往右,從小到大)
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,10,5,6};
System.out.println(isSorted(array));
}
public static boolean isSorted(int[] array){
for (int i = 0; i < array.length-1; i++) {
// 注意 array.length-1,為什么減一呢?因為你想想看,假設有6個元素(array.length == 6)
// 但是下標最大為 5 == array.length-1,因為有小于號,所以這個減一,可以被省略,那為什么還要減一?
// 注意我們的if條件(array[i]>array[i+1]),當回圈元素到下標為5的元素(最后一個元素),就會有問題了
// array[i+1] == array[6] == 第七個元素,第七個元素有沒有?沒有,那我們訪問的話會產生陣列越界訪問錯誤
// 圖35
if(array[i]>array[i+1]){// 左邊的元素比右邊的元素大,那么就不滿足升序,稱為亂序
return false;// 亂序
}
}
return true;// 有序
}
}// 圖34
圖34

圖35

?
陣列排序(冒泡排序)
升序
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {9,5,2,7};// 我們假設一個整形陣列
bubbleSort(array);
// 呼叫我們的自定義的冒泡的方法,把我們的陣列名(參考)扔過去,按參考傳遞
System.out.println(Arrays.toString(array));// 偷個油,不用回圈列印,將其轉換成字串輸出
}
public static void bubbleSort(int[] array){// 創建一個 陣列變數,來接收傳參
// 理一下思緒,首先假設我定義一個 i 來表示元素下標,通過參考(陣列名) 和 [] 來訪問下標所對應的函式,
//既然要排升序,肯定要比較大小,不可能自己跟自己比吧?要跟它后面的元素比,比它大,相互交換位置,反則什么都不做(升序),
// 但是不可能只比一次,我這里有四個元素,至少要比3次,才能完成把最大的數放在最后,
// 有的人可能會說,不是有4個元素嗎?不應該是4次,記住我們2個一比,每次都是前面比后面,
// 到了倒數第二個元素,它是最后的元素相比較,比較完了,那么最后一個元素已經最大的了,還有比較的意義嗎?沒有!
//而且這是,一趟,還要比較3趟,我們第一趟比較只是把最大的數,放到了最后,其它三個數,還不知是否是升序
圖 36
// 現在我們正式開始
for (int i = 0; i < array.length; i++) {// 有4個元素,需要比 3 趟
// 根據 圖36 最后的結論,表示有可能,在未來完成某一趟比較之后,后面的數值已經有序,那我們沒有比較的必要
// 所以 我們在這里定義一個 flag = 1,再在 交換程式中 寫一個flag=0;
// 什么意思呢? 就是你只要交換了兩元素的位置,說明這一趟,陣列肯定不是有序的,你都交換了,還有序?
// 如果 這一趟下來flag還是等于1,我們結束整個排序,為什么?因為根據圖36來看,冒泡排序的比較模式 是交換式比較,
// 1 和 2 一比,比完; 2 和 3一比,也就是如果flag等于1,說明后面沒有發生交換
// 后面的每一位都比自身前一位都要大(比前面的位,早在之前就給你換了)
// 說明升序排列完成
int flag =1;// 假設這一趟是有序的
// 每一趟的比較程序
for (int j = 0; j < array.length-1-i; j++) {// 減一是為了防止越界,這個應該都懂
// 至于減 i,想想看,我們每一趟比較,把最大的數往后排,小的數往前挪,作為下一次標膠的起點
// 再加上這一趟比下來,可以說一個數跟其他都比較了,只有全比較了,我們才能知道最大數究竟是誰?
// 得出了最大數,放在最后,那還有比較的必要,再去比,就是瘋了,(都打過一架了,還輸了,你還找別人去單挑,不是瘋了,就是zz)
// 所以每比完一趟,我們比較次數就減一,
// 第一次,i==0,是因為倒數2個大值,還需要比較,你再減一個1,還比什么,搞黑手?還沒比,就把最后的一位數,放在最后一位
// 萬一倒數第二位,比最后的數,要大呢?,這不是搞黑幕,是搞什么?嗯?
if(array[j]>array[j+1]){
// 升序,前者比后者小,只要前者比后者大,就意味著需要交換位置
int tmp = array[j];
array[j] = array[j+1];
array[j+1]=tmp;
// 假設
// 2 1
// tmp = 2 == array[0] ; array[0] = array[1] == 1,此時array[0]已經被改變
// array [1] = tmp ==2;
// 即 陣列元素順序 為 1,2
flag = 0;// 都交換了,那么肯定是不是有序的
}
}
if(1== flag){
break;//如果flag等于1,說明后面的每一位都比自身前一位都要大,那就說明沒有比較的意義,同時意味著排序完成,跳出回圈,
}
}
來看看看結果 圖 37
}
}
圖36

圖37

?
經過上面的講解,至少你對冒泡有一定的了解,很遺憾,我想告訴你,我們辛辛苦苦做出的冒泡排序,在Java是有函式可以做到的(但并不意味我們剛才的努力都是白費,萬一面試官,讓你模擬實作一個冒泡排序呢?)對吧? 廢話不多說,我們來看看這哥函式是什么?
Arrays.sort
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {9,5,2,7};
Arrays.sort(array);// 是借助Java工具Arrays.sort來完成的,圖 39
System.out.println(Arrays.toString(array));// 圖38
}
}
圖38

圖39

?
我們在順便拓展一下 Arrays 的其它功能
Arrays.fill
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = new int[10];// 此時陣列默認10個元素都是0,圖40
Arrays.fill(array,99);// fill 是 填的意思,圖 42
System.out.println(Arrays.toString(array));// 效果見 圖 41
}
}
圖 40

圖41

圖42

?
根據圖 43,發現 Arrays,fill 的引數,還可以寫兩個
圖43

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = new int[10];// 此時陣列默認10個元素都是0,圖40
Arrays.fill(array,0,5,99);// 意思將下標為0的元素到下標為4的元素全部置為0
// 至于為什么不是下標為5,是因為 該范圍是 左閉右開 [0,5) == 0=<下標 && 下標<5
System.out.println(Arrays.toString(array));// 效果見 圖 44
}
}
圖44

陣列逆序
假設陣列元素順序為 1,2,3,4,5(并不一定是有序,只是為了舉例方便)
結果為 5,4,3,2,1
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
echange(array);
System.out.println(Arrays.toString(array));// 圖 45
}
public static void echange(int[] array){
int left =0;// 左下標
int right = array.length-1;// 右下標
while(left<right){
// 就是兩邊的資料對著換
// 當left 和 right 所指向的下標相遇是,也就同一個元素
// 回圈終止
int tmp = array[left];
array[left]=array[right];
array[right]= tmp;
right--;
left++;
}
}
}
圖45

?
陣列數字排列
給定一個整型陣列, 將所有的偶數放在前半部分, 將所有的奇數放在陣列后半部分
例如
{1, 2, 3, 4}
調整后得到
{4, 2, 3, 1}
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4};
transform(array);
System.out.println(Arrays.toString(array));// 圖 46
}
public static void transform(int[] array){
int left = 0;
int right = array.length-1;
while(left<right){
while(left<right && array[left]%2 == 0){
// 找奇數(%2 !=0),找到了,跳出回圈
left++;
// left 是不能一直加加的,如果沒有 left<right 這個限制條件,在交換完成(left和right相遇),該下標還會一直 ++,
// 甚至可能會越界(全偶數),因為(小)回圈體執行完了,才會去判斷(大)回圈條件,
}
while(left<right && array[right]%2 != 0 ){
// 找偶數(%2 == 0),找到了,跳出回圈
right--;// 這個與left同理
}
int tmp = array[left];
array[left] = array[right];
array[right] = tmp;
}
}
}
圖46

?
陣列拷貝
拷貝方法1 回圈拷貝
假設你要拷貝的陣列 是 int[] array = {1,2,3,4,5}
那么我就需要 創一個相同型別,元素個數相同的 陣列變數array2來接收(int[] array2 [array.length])
通過 對應的下標進行復制拷貝
代碼如下
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array={1,2,3,4,5};
int[] array2 = copyOf(array);// 是方法中 參考ret存盤值的一份拷貝,能夠訪問 ret 指向的堆上的物件
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(array2));// 圖 47
}
public static int[] copyOf(int[] array){
int[] ret = new int[array.length];//創一個相同型別,元素個數相同的 陣列變數array2來接收 array 的元素
for (int i = 0; i < array.length; i++) {
ret[i] = array[i];//通過 對應的下標進行復制拷貝
}
return ret;// 將物件的地址轉過去
}
}// 圖 48
圖47

圖48

?
方法2
利用Java提供的函式: Arrays.copyOf
圖49
圖 49

代碼如下
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] array2 = Arrays.copyOf(array,array.length);
System.out.println(Arrays.toString(array2));// 圖 50
// 既然能規定 拷貝數量,我輸入拷貝數量超過,源陣列array的元素個數呢?
int[] array3 = Arrays.copyOf(array,array.length*2);
System.out.println(Arrays.toString(array3));// 圖 51,由圖可知類似擴容
}// 但是注意一點,本質是copy明白嘛? 這擴容出來的陣列,跟元素組,不是同一個陣列
左鍵點擊copyOf +Ctrl+左鍵),來看看得到的 圖52 ,由圖52,還可以得知 如果我們想"擴容",輸入的倍數必須整數,因為它的長度型別規定為整形
}
圖50

圖51

圖52

?
方法3
不知道你們注意到沒? 圖52中的一個程式陳述句
圖 53
圖中所圈部分,就是我們拷貝陣列的第三種方法
圖53

但是我們先來看第四種方法,為第三種方法做鋪墊
Arrays.copyOfRange()
圖54

代碼如下
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] ret = Arrays.copyOfRange(array,0,4);
System.out.println(Arrays.toString(ret));//圖 55
}
}
圖 55

?
好,現在我們來看看 第三方法

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] array2 = new int[array.length];
System.arraycopy(array,0,array2,0,array.length);
// 跟用for回圈進行拷貝時一個道理,根據對應的下標進行賦值拷貝
System.out.println(Arrays.toString(array2));
// 圖 56
}
}
圖56

?
拓展
圖 57

注意圖中所圈部分,怎么進我就不再教了,忘了就往上翻,
我來提示你,System.arraycopy是不是沒有實作程序,只是一個類似函式宣告一樣,放在那里?
那它是怎么實作陣列拷貝的呢?
這就跟我們所圈起來的native(本地的)有關,
所有被 native 所修飾的方法,方法的實作程序,都已經被 C/C++ 實作了,
我們是看不到運行程序的,這樣寫的最大好處就是 速度快,效率高
?
方法 5 陣列克隆
基本語法:
陣列名.clone();
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[] array = {1,2,3,4,5};
int[] array2 = array.clone();// 類似 副本,不是游戲副本啊!
// 可以理解為是一份資料的備份
System.out.println(Arrays.toString(array2));
}// 圖58
}
圖58

?
在 一維數組的最后我們在講一個概念, 深拷貝 和 前拷貝
圖 59

&ensp;
二維陣列
二維陣列的創建
基本語法1
資料型別[][] 陣列名 = { 初始化資料 }
基本語法2
資料型別[][] 陣列名 = new 資料型別[][]{ 初始化資料 }
基本語法3
資料型別[][] 陣列名 = new 資料型別[行數][列數]
跟一維陣列幾乎一樣,只要初始化了資料,你的[][]里就不能有數字的存在
代碼如下
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
// 創建一個 2行3列的二維陣列
int[][] array = {{1,2,3},{4,5,6}};
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
int[][] array3 = new int[2][3];
}
}
?
二維陣列的列印
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
// 創建一個 2行3列的二維陣列
int[][] array = {{1,2,3},{4,5,6}};
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
int[][] array3 = new int[2][3];
print(array);
}
public static void print(int[][] array){
// 按照我們以前對C的理解,二維陣列的存盤模式應該為 圖60
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
//列印一行資料
System.out.print(array[i][j] + " ");
}
System.out.println();// 換行
}
}
}// 效果圖 61
圖60

圖 61

由圖的結果來看沒問題
但是我總不能,每個二維陣列都自己去算它有幾個元素吧,
問題就在于怎么去獲得 行 和 列
這里就參考C語言的一個概念,二維陣列是一個特殊的一維陣列
經過前面講解,大家都知道陣列是存盤在堆上的,再加上面這句話的概念
讓我們看看圖62
圖 62

接著我們來對上面的程式(二維陣列的列印)進行改良
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
// 創建一個 2行3列的二維陣列
int[][] array = {{1,2,3},{4,5,6}};
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
int[][] array3 = new int[2][3];
print(array);
// 這里我們在用實體證明一下
// array.length 是否能的得到 行數 2
System.out.println(array.length);
// array[下標].length 是否能得到 列數3
System.out.println(array[0].length);
System.out.println(array[1].length);
}
public static void print(int[][] array){
// 按照我們以前對C的理解,二維陣列的存盤模式應該為圖60
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
//列印一行資料
System.out.print(array[i][j] + " ");
}
System.out.println();// 換行
}
}
}// 圖63
圖63

?
前面使用for回圈來列印陣列,這回我們foreach
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[][] array = {{1,2,3},{4,5,6}};
print(array);
}
public static void print(int[][] array){
for (int[] ret:array) {// array元素的資料型別是一個一維陣列,我就需要一個相同的型別的變數來接收
for (int x:ret) {
// ret是一個一維陣列的陣列名,接下來就跟前面使用foreach是一樣,將 參考ret 所指向的物件(陣列)的元素,
// 讀取并賦值給 與其元素型別相同的變數, 我們再將其輸出,就可以了
System.out.print(x + " " );
}
System.out.println();//換行
}
}
}// 圖 64
圖64

?
還有一種輸出二維陣列的方法
在前面,我們使用了 Arrays.toString,將陣列轉換的字串輸出
二維陣列也有對應的 方法: Arrays.deepToString(陣列名)
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[][] array = {{1,2,3},{4,5,6}};
System.out.println(Arrays.deepToString(array));
}
}//圖 65
圖65

?
接下來,我會讓你們見識到一種特別的二維陣列
代碼案例
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[][] array = {{1,2},{1,2,3}};
for (int[] ret:array) {
for (int x:ret) {
System.out.print(x+" ");
}
System.out.println();// 換行
}
}
}//圖 66,見證奇跡,參考圖62
圖66


?
再來舉個例子
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[][] array = new int[2][];
// 在C語言中,二維陣列,是不能省略列的,行可以省略
// 而Java與之相反,行不能省略,列可以(圖67、68)
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();// 換行
}
}//圖 69,圖 70
}
圖67

圖68

圖69

圖70

?
哪有人可能會問,雖然寫法沒問題,但是程式運行會報錯,那么省略列的意義在哪?
意義在于我們可以改,去賦予
這種二維陣列,我們將其稱為 不規則的二維陣列,
代碼如下
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
public static void main(String[] args) {
int[][] array = new int[2][];
array[0]=new int[3];// 意味著第一個陣列長度為3
array[1]=new int[2];// 意味著第二個陣列長度為2
System.out.println(Arrays.deepToString(array));
}
}// 圖71,72
圖71

圖72

本文結束,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/341872.html
標籤:java
