一、數組的概述
1.1 什麼是數組?
數組(Array)是多個相同類型數據按一定順序排列的集合,並使用一個名字命名,並通過編號的方式對這些數據進行統一管理。
1.2 數組的相關概念
數組名
下標(或索引)
元素
數組的長度
1.3 數組的特點
(1)創建數組對象會在內存中開闢一整塊連續的空間,而數組名中引用的是這塊連續空間的首地址。
(2)數組本身是引用數據類型,而數組中的元素可以是任何數據類型,包括基本數據類型和引用數據類型。
(3)數組的長度一旦確定,就不能修改。
(4)數組是有序排列的,我們可以直接通過下標(或索引)的方式獲取指定位置的元素,速度很快。
1.4 數組的分類
按照維度分:一維數組、二維數組、多維數組
按照元素的數據類型分:基本數據類型元素的數組、引用數據類型元素的數組(即對象數組)
二、一維數組的使用
2.1 數組的聲明和初始化
2.1.1 靜態初始化
靜態初始化是指:數組的初始化和數組元素的賦值操作同時進行
int[] ids=new int[]{1001,1002,1003,1004};
2.1.2 動態初始化
動態初始化是指:數組的初始化和數組元素的賦值操作分開進行
String[] names=new String[4];
names[0]="張三";//數組的下標(索引)從0開始,到數組的長度-1結束
names[1]="李四";
names[2]="王五";
names[3]="趙六";
注意:數組初始化時,要指定數組的長度,因爲只有確定了數組的長度之後,才能在內存中開闢所需要的空間。
並且數組一旦初始化完成,其長度就確定了。
2.2 調用數組指定位置的元素(通過下標調用)
System.out.println("id:"+ids[0]+",name:"+names[0]);
System.out.println("id:"+ids[1]+",name:"+names[1]);
System.out.println("id:"+ids[2]+",name:"+names[2]);
System.out.println("id:"+ids[3]+",name:"+names[3]);
2.3 獲取數組的長度
通過length屬性獲取
System.out.println(ids.length); //4
System.out.println(names.length); //4
2.4 遍歷數組元素
2.4.1 使用for循環遍歷
for (int i=0;i<ids.length;i++){
System.out.println(ids[i]);
}
2.4.2 使用foreach循環遍歷
for (String name:names) {
System.out.println(name);
}
2.5 數組元素的默認初始化值 2.5.1 對於基本數據類型而言,默認初始化值各有不同
//數組元素是整型(int short long byte):0
int[] arr1=new int[4];
for (int i=0;i<arr1.length;i++){
System.out.println(arr1[i]);
}
System.out.println("-------------------");
short[] arr2=new short[4];
for (int i=0;i<arr2.length;i++){
System.out.println(arr2[i]);
}
System.out.println("-------------------");
long[] arr3=new long[4];
for (int i=0;i<arr3.length;i++){
System.out.println(arr3[i]);
}
System.out.println("-------------------");
byte[] arr4=new byte[4];
for (int i=0;i<arr4.length;i++){
System.out.println(arr4[i]);
}
運行結果:
//數組元素是浮點型(double float):0.0
double[] arr5=new double[4];
for (int i=0;i<arr5.length;i++){
System.out.println(arr5[i]);
}
System.out.println("-------------------");
float[] arr6=new float[4];
for (int i=0;i<arr6.length;i++){
System.out.println(arr6[i]);
}
運行結果:
//數組元素是char型:0(表現爲空)
char[] arr7=new char[4];
for (int i=0;i<arr7.length;i++){
System.out.println(arr7[i]);
}
運行結果:
//數組元素是boolean型:false
boolean[] arr8=new boolean[4];
for (int i=0;i<arr8.length;i++){
System.out.println(arr8[i]);
}
運行結果:
//數組元素是引用數據類型:null
String[] arr9=new String[4];
for (int i=0;i<arr9.length;i++){
System.out.println(arr9[i]);
}
運行結果:
2.6 數組的內存解析
new出來的對象、數組都存放在堆中;
局部變量都存放在棧中。
1. int[] arr = new int[4];
2. arr1[1] = 1;
arr1[2] = 2;
3. arr1 = new int[5];
4. System.out.println(arr1[1]);//0
當執行第1步時,會先在堆中開闢出數組所需要的內存空間,初始化值爲0,如下圖所示:
當執行第2步,爲數組元素賦值時,如下圖所示:
當執行第3步,會在堆中重新開闢新的內存空間,然後改變arr1的首地址指向,如下圖所示:
當執行第4步,會輸出新的內存空間的默認值,所以輸出結果爲0。
三、二維數組的使用
二維數組是以數組作爲數組元素的數組,即“數組的數組”。
對於二維數組的理解,我們可以看成是一維數組array1又作爲另一個一維數組array2的元素而存在。
3.1 數組的聲明和初始化
3.1.1 靜態初始化
靜態初始化是指:數組的初始化和數組元素的賦值操作同時進行
int[][] arr1=new int[][]{{1,2,3},{4,5},{6,7,8}};
3.1.2 動態初始化
動態初始化是指:數組的初始化和數組元素的賦值操作分開進行
//動態初始化1
int[][] arr2=new int[2][2];
arr2[0][0]=1;
arr2[0][1]=2;
arr2[1][0]=3;
arr2[1][1]=4;
//動態初始化2
int[][] arr3=new int[2][];
//爲數組中第一個元素賦值
arr3[0]=new int[2];
//爲數組中第一個元素中的元素賦值
arr3[0][0]=1;
arr3[0][1]=2;
//爲數組中第二個元素賦值
arr3[1]=new int[3];
//爲數組中第二個元素中的元素賦值
arr3[1][0]=3;
arr3[1][1]=4;
arr3[1][2]=5;
3.2 調用數組指定位置的元素(通過下標調用)
System.out.println(arr2[1][0]);//3
//注意:使用動態初始化方式2時,必須先賦值才能調用,否則會報空指針異常
System.out.println(arr3[1][2]);//5
3.3 獲取數組的長度
通過length屬性獲取
int[][] arr1=new int[][]{{1,2,3},{4,5},{6,7,8}};
//獲取外層數組的長度
System.out.println(arr1.length);//3
//獲取內層數組的長度
System.out.println(arr1[0].length);//3
System.out.println(arr1[1].length);//2
System.out.println(arr1[2].length);//3
3.4 遍歷數組元素
使用嵌套for循環遍歷
int[][] arr1=new int[][]{{1,2,3},{4,5},{6,7,8}};
for (int i=0;i<arr1.length;i++){
for (int j=0;j<arr1[i].length;j++){
System.out.print(arr1[i][j]+" ");
}
System.out.println();
}
遍歷結果
3.5 二維數組元素的默認初始化值
規定:二維數組分爲外層數組的元素,內層數組的元素
int[][] arr = new int[4][3];
外層元素: arr[0],arr[1],arr[2],arr[3]
內層元素: arr[0][0],arr[1][2]等
針對於動態初始化方式一:比如: int[][] arr = new int[4][3];
外層元素的初始化值爲:地址值
內層元素的初始化值爲:與一維數組初始化情況相同
針對於初始化方式二:比如: int[][] arr = new int[4][];
外層元素的初始化值爲: null (因爲數組是引用類型,默認值爲null)
內層元素的初始化值爲:不能調用,否則會報空指針異常。
//動態初始化方式一
int[][] arr4= new int[3][2];
System.out.println(arr4[0]);//[I@4554617c [表示一維數組 I表示int類型 @4554617c表示首地址值
System.out.println(arr4[0][0]);//0
System.out.println("-------------------");
String[][] arr5= new String[3][2];
System.out.println(arr5[0]);//[Ljava.lang.String;@74a14482
System.out.println(arr5[0][0]);//null
運行結果:
//動態初始化方式二
int[][] arr6= new int[3][];
System.out.println(arr6[0]);//null (因爲數組是引用類型,默認值爲null)
System.out.println(arr6[0][0]);//Exception in thread "main" java.lang.NullPointerException
運行結果:
3.6 二維數組的內存解析
1. int[][] arr1 = new int[4][];
2. arr1[1] = new int[]{1,2,3};
3. arr1[2] = new int[4];
4. arr1[2][1] = 30;
當執行第1步時,會先在堆中開闢出數組所需要的內存空間,初始化值爲null,如下圖所示:
當執行第2步,爲數組元素arr1[1]賦值時,如下圖所示:
當執行第3步,爲數組元素arr1[2]賦值時,如下圖所示:
當執行第4步,爲數組元素arr1[2][1]賦值時,如下圖所示:
四、數組中常見的算法
4.1 數組的複製
public class ArrayTest {
public static void main(String[] args) {
//數組的複製
String[] arr1=new String[]{"A","B","C","D","E"};
String[] arr2=new String[arr1.length];
for (int i=0;i<arr1.length;i++){
arr2[i]=arr1[i];
}
//打印出複製後的數組
for (int i=0;i<arr2.length;i++){
System.out.println(arr2[i]);
}
}
}
運行結果:
4.2 數組的反轉
public class ArrayTest2 {
public static void main(String[] args) {
//數組元素的反轉
String[] arr=new String[]{"A","B","C","D","E"};
for (int i=0;i<arr.length/2;i++){ //相當於把A和E、B和D的位置顛倒一下
String temp=arr[i];
arr[i]=arr[arr.length-i-1];
arr[arr.length-i-1]=temp;
}
//打印出反轉後的數組
for (int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
}
}
運行結果:
4.3 數組的查找
4.3.1 線性查找
線性查找又稱順序查找,是一種最簡單的查找方法,它的基本思想是從第一個記錄開始,逐個比較記錄的關鍵字,直到和給定的K值相等,則查找成功;若比較結果與文件中n個記錄的關鍵字都不等,則查找失敗。
public class ArrayTest3 {
public static void main(String[] args) {
//線性查找
String[] arr=new String[]{"A","B","C","D","E"};
String target="C"; //要查找的目標元素
//定義一個標識符,用來表示是否查到了目標 false:沒找到 true:查找到了
boolean flag=false;
for (int i=0;i<arr.length;i++){
if(target.equals(arr[i])){
System.out.println("查找到了目標元素,位置爲:"+i);
flag=true;
break;
}
}
if(flag=false){
System.out.println("未查找到目標元素!");
}
}
}
運行結果:
4.3.2 二分法查找
二分法查找又稱折半查找,二分法查找的基本思想是設數組中的元素從小到大有序地存放在數組中(注:二分法查找的關鍵,首先數組元素必須從小到大有序排列)
- 首先將給定值target與數組中間位置上元素的值(key)比較,如果相等,則查找成功;
- 否則,若target小,則在數組前半部分中繼續進行二分法查找;
- 若target大,則在數組後半部分中繼續進行二分法查找。
這樣,經過一次比較就縮小一半的查找區間,如此進行下去,直到查找成功或查找失敗。
public class ArrayTest4 {
public static void main(String[] args) {
//二分法查找
int[] arr =new int[]{1,3,5,6,7,10,12,36,66,88};
int target=12; //要查找的目標
int head=0; //首索引
int end=arr.length-1; //末索引
//定義一個標識符,用來表示是否查到了目標 false:沒找到 true:查找到
boolean flag=false;
while (head<=end){
int middle=(head+end)/2; //中間位置的索引
if(target==arr[middle]){
System.out.println("查找到了目標元素,位置爲:"+middle);
flag=true;
break;
}else if(target<arr[middle]){
end=middle-1;
}else { //target>arr[middle]
head=middle+1;
}
}
if(flag=false){
System.out.println("未查找到目標元素!");
}
}
}
運行結果:
4.4 數組的排序
4.4.1 冒泡排序
排序思想:
- 比較相鄰的元素。如果第一個比第二個大(升序),就交換他們兩個。
- 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
- 針對所有的元素重複以上的步驟,除了最後一個。
- 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較爲止。
排序方法演示
代碼實現
public class BubbleSort {
public static void main(String[] args) {
int[] arr =new int[]{3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
//冒泡排序
for (int i=0;i<arr.length-1;i++){ //外循環爲排序趟數,n個數進行n-1趟
//內循環爲每趟比較的次數,第i趟比較n-i次
for (int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){ //相鄰元素比較,如果前一個元素比後一個大,則交換兩者的位置
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
//輸出排序後的數組
for (int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
}
}
運行結果:
4.4.2 快速排序
快速排序是迄今爲止所有內排序算法中速度最快的一種。它的基本思想是:任取待排序序列中的某個元素作爲標準(也稱爲支點、界點一般取第一個元素),通過一次劃分,將待排元素分爲左右兩個子序列,左子序列元素的排序碼均小於基準元素的排序碼,右子序列的排序碼則大於或等於基準元素的排序碼,然後分別對兩個子序列繼續進行劃分,直至每一個序列只有一個元素爲止。最後得到的序列便是有序序列。
排序方法演示
代碼實現
public class QuickSort {
public static void quickSort(int[] arr,int low,int high){
int i,j,base;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基準位
base = arr[low];
while (i<j) {
//先看右邊,依次往左遞減
while (base<=arr[j]&&i<j) {
j--;
}
//再看左邊,依次往右遞增
while (base>=arr[i]&&i<j) {
i++;
}
//如果滿足條件則交換
if (i<j) {
int t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最後將基準爲與i和j相等位置的數字交換
arr[low] = arr[i];
arr[i] = base;
//遞歸調用左半數組
quickSort(arr, low, j-1);
//遞歸調用右半數組
quickSort(arr, j+1, high);
}
public static void main(String[] args){
int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
運行結果:
4.5 Arrays工具類的使用
java.util.Arrays類即爲操作數組的工具類,包含了用來操作數組(比如排序和搜索)的各種方法。
4.5.1 boolean equals(int[] a,int[] b) 判斷兩個數組是否相等
//boolean equals(int[] a,int[] b) 判斷兩個數組是否相等
int[] arr1=new int[]{1,2,3,4,5};
int[] arr2=new int[]{1,3,5,7,9};
int[] arr3=new int[]{1,3,5,7,9};
boolean isEquals=Arrays.equals(arr1, arr2);
boolean isEquals2=Arrays.equals(arr2, arr3);
System.out.println(isEquals); //false
System.out.println(isEquals2); //true
運行結果:
4.5.2 String toString(int[] a) 輸出數組信息
// String toString(int[] a) 輸出數組信息
int[] arr1=new int[]{1,2,3,4,5};
System.out.println(Arrays.toString(arr1));
運行結果:
4.5.3 void fill(int[] a,int val) 將指定值填充到數組之中
int[] arr1=new int[]{1,2,3,4,5};
System.out.println(Arrays.toString(arr1)); //輸出原數組
Arrays.fill(arr1,6); //將指定值填充到數組之中
System.out.println(Arrays.toString(arr1)); //輸出用指定值填充過的數組
運行結果:
4.5.4 void sort(int[] a) 對數組進行排序
int[] arr1=new int[]{6,2,5,3,1,8};
Arrays.sort(arr1); //對數組進行排序
System.out.println(Arrays.toString(arr1)); //輸出排序後的數組
運行結果:
4.5.5 int binarySearch(int[] a,int key) 對排序後的數組使用二分法檢索指定的值
int[] arr1=new int[]{1,2,5,7,13,28,36};
int index=Arrays.binarySearch(arr1,7); //使用二分法檢索指定的值,返回值爲正數時,則爲查找值的索引位置;返回值爲負數,表示未查找到
System.out.println(index);
運行結果:
4.6 數組中常見的異常
數組也是Java中一個非常重要的知識點,無論是在日常開發還是面試和筆試中都經常用到。希望本篇文章能夠對你有所幫助。