第04章_數(shù)組

學(xué)習(xí)目標(biāo)

  • 理解容器的概念
  • 掌握一維的聲明和初始化
  • 使用索引訪問數(shù)組的元素
  • 掌握數(shù)組的遍歷
  • 了解數(shù)組的內(nèi)存圖解
  • 熟悉空指針和數(shù)組角標(biāo)越界異常
  • 掌握數(shù)組基礎(chǔ)算法
    • 掌握數(shù)組元素的統(tǒng)計(jì)分析
    • 掌握數(shù)組最大值的獲取
    • 掌握數(shù)組元素的查找
    • 掌握數(shù)組元素的反轉(zhuǎn)
    • 掌握數(shù)組的排序

1. 數(shù)組的概述

1.1 容器概述

需求分析1:

現(xiàn)在需要統(tǒng)計(jì)某公司50個(gè)員工的工資情況,例如計(jì)算平均工資、找到最高工資等。用前面所學(xué)的知識(shí)答毫,首先需要聲明50個(gè)變量來(lái)分別記住每位員工的工資锦秒,這樣做會(huì)顯得很麻煩娄猫。因此我們可以使用容器進(jìn)行操作卓起,將所有的數(shù)據(jù)全部存儲(chǔ)到一個(gè)容器中兴蒸,統(tǒng)一操作衫生。

容器概念:

  • 生活中的容器:水杯(裝水等液體)裳瘪,衣柜(裝衣服等物品),教室(裝學(xué)生等人員)罪针。
  • 程序中的容器:是將多個(gè)數(shù)據(jù)存儲(chǔ)到一起彭羹,每個(gè)數(shù)據(jù)稱為該容器的元素。

1.2 數(shù)組的概念

  • 數(shù)組(Array)泪酱,是多個(gè)相同類型數(shù)據(jù)按一定順序排列的集合派殷,并使用一個(gè)名字命名还最,并通過(guò)編號(hào)的方式對(duì)這些數(shù)據(jù)進(jìn)行統(tǒng)一管理。

  • 數(shù)組中的概念

    • 數(shù)組名
    • 下標(biāo)(或索引)
    • 元素
    • 數(shù)組的長(zhǎng)度

數(shù)組的特點(diǎn):

  • 數(shù)組本身是引用數(shù)據(jù)類型毡惜,而數(shù)組中的元素可以是任何數(shù)據(jù)類型拓轻,包括基本數(shù)據(jù)類型和引用數(shù)據(jù)類型。

  • 創(chuàng)建數(shù)組對(duì)象會(huì)在內(nèi)存中開辟一整塊連續(xù)的空間经伙,而數(shù)組名中引用的是這塊連續(xù)空間的首地址扶叉。

  • 數(shù)組的長(zhǎng)度一旦確定,就不能修改帕膜。

  • 我們可以直接通過(guò)下標(biāo)(或索引)的方式調(diào)用指定位置的元素枣氧,速度很快。

1.3 數(shù)組的分類

1垮刹、按照維度分:

  • 一維數(shù)組:存儲(chǔ)一組數(shù)據(jù)
  • 二維數(shù)組:存儲(chǔ)多組數(shù)據(jù)达吞,相當(dāng)于二維表,一行代表一組數(shù)據(jù)危纫,只是這里的二維表每一行長(zhǎng)度不要求一樣。

2乌庶、按照元素類型分:

  • 基本數(shù)據(jù)類型的元素:存儲(chǔ)基本數(shù)據(jù)類型的值
  • 引用數(shù)據(jù)類型的元素:存儲(chǔ)對(duì)象(本質(zhì)上存儲(chǔ)對(duì)象的首地址)(這個(gè)在面向?qū)ο蟛糠种v解)

2. 一維數(shù)組的使用

2.1 一維數(shù)組的聲明

  • 一維數(shù)組的聲明/定義格式
//推薦
元素的數(shù)據(jù)類型[] 數(shù)組的名稱;

//不推薦
元素的數(shù)據(jù)類型  數(shù)組名[];

舉例:

int a[];
int[] a1;
double  b[];
String[] c;  //引用類型變量數(shù)組
  • 數(shù)組的聲明种蝶,就是要確定:

(1)數(shù)組的維度:在Java中數(shù)組的標(biāo)點(diǎn)符號(hào)是[],[]表示一維瞒大,[][]表示二維

(2)數(shù)組的元素類型:即創(chuàng)建的數(shù)組容器可以存儲(chǔ)什么數(shù)據(jù)類型的數(shù)據(jù)螃征。可以是基本數(shù)據(jù)類型透敌,也可以是引用數(shù)據(jù)類型盯滚。例如:int, String, Student等

(3)數(shù)組名:就是代表某個(gè)數(shù)組的標(biāo)識(shí)符,數(shù)組名其實(shí)也是變量名酗电,按照變量的命名規(guī)范來(lái)命名魄藕。數(shù)組名是個(gè)引用數(shù)據(jù)類型的變量,因?yàn)樗硪唤M數(shù)據(jù)撵术。

  • 示例
public class Test01ArrayDeclare {
    public static void main(String[] args) {
        //比如背率,要存儲(chǔ)一個(gè)小組的成績(jī)
        int[] scores;
        int grades[];
//        System.out.println(scores);//未初始化不能使用

        //比如,要存儲(chǔ)一組字母
        char[] letters;

        //比如嫩与,要存儲(chǔ)一組姓名
        String[] names;

        //比如寝姿,要存儲(chǔ)一組價(jià)格
        double[] prices;

    }
}

注意:Java語(yǔ)言中聲明數(shù)組時(shí)不能指定其長(zhǎng)度(數(shù)組中元素的數(shù))。 例如: int a[5]; //非法

2.2 一維數(shù)組的初始化

2.2.1 靜態(tài)初始化

  • 什么是靜態(tài)初始化划滋?

  • 靜態(tài)初始化就是用靜態(tài)數(shù)據(jù)(編譯時(shí)已知)為數(shù)組初始化饵筑。此時(shí)數(shù)組的長(zhǎng)度由靜態(tài)數(shù)據(jù)的個(gè)數(shù)決定。

  • 一維數(shù)組靜態(tài)初始化格式1:

    數(shù)據(jù)類型[] 數(shù)組名 = new 數(shù)據(jù)類型[]{元素1,元素2,元素3...};
    
    或
        
    數(shù)據(jù)類型[] 數(shù)組名;
    數(shù)組名 = new 數(shù)據(jù)類型[]{元素1,元素2,元素3...};
    
    • new:關(guān)鍵字处坪,創(chuàng)建數(shù)組使用的關(guān)鍵字根资。因?yàn)閿?shù)組本身是引用數(shù)據(jù)類型架专,所以要用new創(chuàng)建數(shù)組對(duì)象。

    例如嫂冻,定義存儲(chǔ)1胶征,2,3桨仿,4睛低,5整數(shù)的數(shù)組容器。

    int[] arr = new int[]{1,2,3,4,5};//正確
    //或
    int[] arr;
    arr = new int[]{1,2,3,4,5};//正確
    
  • 一維數(shù)組靜態(tài)初始化格式2:

    數(shù)據(jù)類型[] 數(shù)組名 = {元素1,元素2,元素3...};//必須在一個(gè)語(yǔ)句中完成服傍,不能分開兩個(gè)語(yǔ)句寫
    

例如钱雷,定義存儲(chǔ)1,2吹零,3罩抗,4,5整數(shù)的數(shù)組容器

int[] arr = {1,2,3,4,5};//正確

int[] arr;
arr = {1,2,3,4,5};//錯(cuò)誤
  • 舉例
public class Test02ArrayInitialize {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};//右邊不需要寫new int[]

        int[] nums;
        nums = new int[]{10,20,30,40}; //聲明和初始化在兩個(gè)語(yǔ)句完成灿椅,就不能使用new int[]

        char[] word = {'h','e','l','l','o'};

        String[] heros = {"袁隆平","鄧稼先","錢學(xué)森"};

        System.out.println("arr數(shù)組:" + arr);//arr數(shù)組:[I@1b6d3586
        System.out.println("nums數(shù)組:" + nums);//nums數(shù)組:[I@4554617c
        System.out.println("word數(shù)組:" + word);//word數(shù)組:[C@74a14482
        System.out.println("heros數(shù)組:" + heros);//heros數(shù)組:[Ljava.lang.String;@1540e19d
    }
}

2.2.2 動(dòng)態(tài)初始化

  • 什么是動(dòng)態(tài)初始化套蒂?

動(dòng)態(tài)初始化就是先確定元素的個(gè)數(shù)(即數(shù)組的長(zhǎng)度),而元素值此時(shí)只是默認(rèn)值茫蛹,還并未真正附自己期望的值操刀。真正期望的數(shù)據(jù)需要后續(xù)單獨(dú)一個(gè)一個(gè)賦值。

  • 格式:
數(shù)組存儲(chǔ)的元素的數(shù)據(jù)類型[] 數(shù)組名字 = new 數(shù)組存儲(chǔ)的元素的數(shù)據(jù)類型[長(zhǎng)度];

或

數(shù)組存儲(chǔ)的數(shù)據(jù)類型[] 數(shù)組名字; 或 數(shù)據(jù)類型 數(shù)組名[]; (括號(hào)在數(shù)組名后也可以)
數(shù)組名字 = new 數(shù)組存儲(chǔ)的數(shù)據(jù)類型[長(zhǎng)度];
  • [長(zhǎng)度]:數(shù)組的長(zhǎng)度婴洼,表示數(shù)組容器中可以最多存儲(chǔ)多少個(gè)元素骨坑。

  • 注意:數(shù)組有定長(zhǎng)特性,長(zhǎng)度一旦指定柬采,不可更改欢唾。和水杯道理相同,買了一個(gè)2升的水杯粉捻,總?cè)萘烤褪?升是固定的礁遣。

  • 舉例1

int[] arr = new int[5];

int[] arr;
arr = new int[5];

int[] arr = new int[5]{1,2,3,4,5};//錯(cuò)誤的,后面有{}指定元素列表肩刃,就不需要在[]中指定元素個(gè)數(shù)了亡脸。
  • 錯(cuò)誤情況:

    //double[] arr = new double[2]{12.3,34.5};
    //double[2] arr1 = new double[2];
    

2.3 一維數(shù)組的使用

2.3.1 數(shù)組的長(zhǎng)度

  • 數(shù)組的元素總個(gè)數(shù),即數(shù)組的長(zhǎng)度
  • 每個(gè)數(shù)組都有一個(gè)屬性length指明它的長(zhǎng)度树酪,例如:a.length 指明數(shù)組a的長(zhǎng)度(元素個(gè)數(shù))
  • 每個(gè)數(shù)組都具有長(zhǎng)度浅碾,而且一旦初始化,其長(zhǎng)度是不可變的

2.3.2 數(shù)組元素的引用

  • 如何表示數(shù)組中的一個(gè)元素续语?

每一個(gè)存儲(chǔ)到數(shù)組的元素垂谢,都會(huì)自動(dòng)的擁有一個(gè)編號(hào),從0開始疮茄,這個(gè)自動(dòng)編號(hào)稱為數(shù)組索引(index)或下標(biāo)滥朱,可以通過(guò)數(shù)組的索引/下標(biāo)訪問到數(shù)組中的元素根暑。

數(shù)組名[索引/下標(biāo)]
  • 數(shù)組的下標(biāo)范圍?

    Java中數(shù)組的下標(biāo)從[0]開始徙邻,下標(biāo)范圍是[0, 數(shù)組的長(zhǎng)度-1]排嫌,即[0, 數(shù)組名.length-1]

  • 數(shù)組元素下標(biāo)可以是整型常量或整型表達(dá)式。如a[3] , b[i] , c[6*i];

  • 舉例

public class Test03ArrayUse {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};

        System.out.println("arr數(shù)組的長(zhǎng)度:" + arr.length);
        System.out.println("arr數(shù)組的第1個(gè)元素:" + arr[0]);//下標(biāo)從0開始  1
        System.out.println("arr數(shù)組的第2個(gè)元素:" + arr[1]); //2
        System.out.println("arr數(shù)組的第3個(gè)元素:" + arr[2]); //3
        System.out.println("arr數(shù)組的第4個(gè)元素:" + arr[3]); //4
        System.out.println("arr數(shù)組的第5個(gè)元素:" + arr[4]); //5

        //修改第1個(gè)元素的值
        //此處arr[0]相當(dāng)于一個(gè)int類型的變量
        arr[0] = 100;
        System.out.println("arr數(shù)組的第1個(gè)元素:" + arr[0]); //100
    }
}

2.4 一維數(shù)組的遍歷

數(shù)組遍歷: 就是將數(shù)組中的每個(gè)元素分別獲取出來(lái)缰犁,就是遍歷淳地。遍歷也是數(shù)組操作中的基石。for循環(huán)與數(shù)組的遍歷是絕配帅容。

  • 舉例1
public class Test05ArrayIterate {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        //打印數(shù)組的屬性颇象,輸出結(jié)果是5
        System.out.println("數(shù)組的長(zhǎng)度:" + arr.length); //5

        //遍歷輸出數(shù)組中的元素
        System.out.println("數(shù)組的元素有:");
        for(int i=0; i<arr.length; i++){
            System.out.println(arr[i]);    
        }
    }
}

//1
//2
//3
//4
//5
  • 舉例2
public class Test06ArrayInitialize {
    public static void main(String[] args) {
        int[] arr = new int[5];

        System.out.println("arr數(shù)組的長(zhǎng)度:" + arr.length); //5
        System.out.print("存儲(chǔ)數(shù)據(jù)到arr數(shù)組之前:[");
        for (int i = 0; i < arr.length; i++) {   //存儲(chǔ)數(shù)據(jù)到arr數(shù)組之前:[0,0,0,0,0]
            if(i==0){
                System.out.print(arr[i]);
            }else{
                System.out.print("," + arr[i]);
            }
        }
        System.out.println("]");

        //初始化
        arr[0] = 2;
        arr[1] = 4;
        arr[2] = 6;
        arr[3] = 8;
        arr[4] = 10;

        for (int i = 0; i < arr.length; i++) {  //arr = {2,4,6,8,10}
            arr[i] = (i+1) * 2;
        }

        System.out.print("存儲(chǔ)數(shù)據(jù)到arr數(shù)組之后:["); 
        for (int i = 0; i < arr.length; i++) { //存儲(chǔ)數(shù)據(jù)到arr數(shù)組之后:[2,4,6,8,10]
            if(i==0){
                System.out.print(arr[i]);
            }else{
                System.out.print("," + arr[i]);
            }
        }
        System.out.println("]");
    }
}

2.5 數(shù)組元素的默認(rèn)值

數(shù)組是引用類型,當(dāng)我們使用動(dòng)態(tài)初始化方式創(chuàng)建數(shù)組時(shí)并徘,元素值只是默認(rèn)值遣钳。例如:

public class Test {
    public static void main(String argv[]){
        int a[]= new int[5]; 
        System.out.println(a[3]); //a[3]的默認(rèn)值為0
    }
} 

對(duì)于基本數(shù)據(jù)類型而言,默認(rèn)初始化值各有不同麦乞。

對(duì)于引用數(shù)據(jù)類型而言蕴茴,默認(rèn)初始化值為null(注意與0不同!)

public class Test07ArrayElementDefaultValue {
    public static void main(String[] args) {
        //存儲(chǔ)26個(gè)字母
        char[] letters = new char[26];
        System.out.println("letters數(shù)組的長(zhǎng)度:" + letters.length);  //letters數(shù)組的長(zhǎng)度:26
        System.out.print("存儲(chǔ)字母到letters數(shù)組之前:[");
        for (int i = 0; i < letters.length; i++) { //存儲(chǔ)字母到letters數(shù)組之前:[0,0,0......0] 26個(gè)
            if(i==0){
                System.out.print(letters[i]);
            }else{
                System.out.print("," + letters[i]);
            }
        }
        System.out.println("]");

       //存儲(chǔ)5個(gè)姓名
        String[] names = new String[5];
        System.out.println("names數(shù)組的長(zhǎng)度:" + names.length); //names數(shù)組的長(zhǎng)度:5
        System.out.print("存儲(chǔ)姓名到names數(shù)組之前:[");
        for (int i = 0; i < names.length; i++) { //存儲(chǔ)姓名到names數(shù)組之前:[null,null,null,null,null]
            if(i==0){
                System.out.print(names[i]);
            }else{
                System.out.print("," + names[i]);
            }
        }
        System.out.println("]");
    }
}

3. 一維數(shù)組內(nèi)存分析

3.1 內(nèi)存概述

內(nèi)存是計(jì)算機(jī)中重要的部件之一姐直,它是與CPU進(jìn)行溝通的橋梁倦淀。其作用是用于暫時(shí)存放CPU中的運(yùn)算數(shù)據(jù),以及與硬盤等外部存儲(chǔ)器交換的數(shù)據(jù)简肴。只要計(jì)算機(jī)在運(yùn)行中晃听,CPU就會(huì)把需要運(yùn)算的數(shù)據(jù)調(diào)到內(nèi)存中進(jìn)行運(yùn)算百侧,當(dāng)運(yùn)算完成后CPU再將結(jié)果傳送出來(lái)砰识。我們編寫的程序是存放在硬盤中的,在硬盤中的程序是不會(huì)運(yùn)行的佣渴,必須放進(jìn)內(nèi)存中才能運(yùn)行辫狼,運(yùn)行完畢后會(huì)清空內(nèi)存。

Java虛擬機(jī)要運(yùn)行程序辛润,必須要對(duì)內(nèi)存進(jìn)行空間的分配和管理膨处。

3.2 Java虛擬機(jī)的內(nèi)存劃分

為了提高運(yùn)算效率,就對(duì)空間進(jìn)行了不同區(qū)域的劃分砂竖,因?yàn)槊恳黄瑓^(qū)域都有特定的處理數(shù)據(jù)方式和內(nèi)存管理方式真椿。

區(qū)域名稱 作用
程序計(jì)數(shù)器 程序計(jì)數(shù)器是CPU中的寄存器,它包含每一個(gè)線程下一條要執(zhí)行的指令的地址
本地方法棧 當(dāng)程序中調(diào)用了native的本地方法時(shí)乎澄,本地方法執(zhí)行期間的內(nèi)存區(qū)域
方法區(qū) 存儲(chǔ)已被虛擬機(jī)加載的類信息突硝、常量、靜態(tài)變量带迟、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)钦讳。
堆內(nèi)存 存儲(chǔ)對(duì)象(包括數(shù)組對(duì)象),new來(lái)創(chuàng)建的芹助,都存儲(chǔ)在堆內(nèi)存护盈。
虛擬機(jī)棧 用于存儲(chǔ)正在執(zhí)行的每個(gè)Java方法的局部變量表等挟纱。局部變量表存放了編譯期可知長(zhǎng)度的各種基本數(shù)據(jù)類型、對(duì)象引用腐宋,方法執(zhí)行完紊服,自動(dòng)釋放。

3.3 一維數(shù)組在內(nèi)存中的存儲(chǔ)

1脏款、一個(gè)一維數(shù)組內(nèi)存圖

public static void main(String[] args) {
    int[] arr = new int[3];
    System.out.println(arr);//[I@5f150435
}

思考:打印arr為什么是[I@5f150435围苫,它是數(shù)組的地址嗎?

答:它不是數(shù)組的地址撤师。

問剂府?不是說(shuō)arr中存儲(chǔ)的是數(shù)組對(duì)象的首地址嗎?

答:arr中存儲(chǔ)的是數(shù)組的首地址剃盾,但是因?yàn)閿?shù)組是引用數(shù)據(jù)類型腺占,打印arr時(shí),會(huì)自動(dòng)調(diào)用arr數(shù)組對(duì)象的toString()方法痒谴,該方法默認(rèn)實(shí)現(xiàn)的是對(duì)象類型名@該對(duì)象的hashCode()值的十六進(jìn)制值衰伯。

問?對(duì)象的hashCode值是否就是對(duì)象內(nèi)存地址积蔚?

答:不一定意鲸,因?yàn)檫@個(gè)和不同品牌的JVM產(chǎn)品的具體實(shí)現(xiàn)有關(guān)。例如:Oracle的OpenJDK中給出了5種實(shí)現(xiàn)尽爆,其中有一種是直接返回對(duì)象的內(nèi)存地址怎顾,但是OpenJDK默認(rèn)沒有選擇這種方式。

2漱贱、數(shù)組下標(biāo)為什么是0開始

因?yàn)榈谝粋€(gè)元素距離數(shù)組首地址間隔0個(gè)單元格槐雾。

3、兩個(gè)一維數(shù)組內(nèi)存圖

兩個(gè)數(shù)組獨(dú)立

public static void main(String[] args) {
    int[] arr = new int[3];
    int[] arr2 = new int[2];
    System.out.println(arr);
    System.out.println(arr2);
}

4幅狮、兩個(gè)變量指向一個(gè)一維數(shù)組

  • 兩個(gè)數(shù)組變量本質(zhì)上代表同一個(gè)數(shù)組募强。首地址值相同
public static void main(String[] args) {
    // 定義數(shù)組崇摄,存儲(chǔ)3個(gè)元素
    int[] arr = new int[3];
    //數(shù)組索引進(jìn)行賦值
    arr[0] = 5;
    arr[1] = 6;
    arr[2] = 7;
    //輸出3個(gè)索引上的元素值
    System.out.println(arr[0]); //5
    System.out.println(arr[1]); //6
    System.out.println(arr[2]); //7
    //定義數(shù)組變量arr2擎值,將arr的地址賦值給arr2
    int[] arr2 = arr;
    arr2[1] = 9; 
    System.out.println(arr[1]); //9 
}

4. 一維數(shù)組的應(yīng)用

4.1 案例1

升景坊單間短期出租4個(gè)月,550元/月(水電煤公攤逐抑,網(wǎng)費(fèi)35元/月)鸠儿,空調(diào)、衛(wèi)生間泵肄、廚房齊全捆交。屋內(nèi)均是IT行業(yè)人士淑翼,喜歡安靜。所以要求來(lái)租者最好是同行或者剛畢業(yè)的年輕人品追,愛干凈玄括、安靜。

public class ArrayTest {
      public static void main(String[] args) {
      int[] arr = new int[]{8,2,1,0,3}; //號(hào)碼中包含的數(shù)
      int[] index = new int[]{2,0,3,2,4,0,1,3,2,3,3}; //對(duì)應(yīng)數(shù)的位置
      String tel = "";
      for(int i = 0;i < index.length;i++){
            tel += arr[index[i]];
      }
      System.out.println("聯(lián)系方式:" + tel); //18013820100
      }
}

4.2 案例2:

從鍵盤讀入學(xué)生成績(jī)肉瓦,找出最高分遭京,并輸出學(xué)生成績(jī)等級(jí)。

  • 成績(jī)>=最高分-10 等級(jí)為’A’

  • 成績(jī)>=最高分-20 等級(jí)為’B’

  • 成績(jī)>=最高分-30 等級(jí)為’C’

  • 其余 等級(jí)為’D’

提示:先讀入學(xué)生人數(shù)泞莉,根據(jù)人數(shù)創(chuàng)建int數(shù)組哪雕,存放學(xué)生成績(jī)。

        //1. 實(shí)例化Scanner,獲取學(xué)生人數(shù)
        Scanner scan = new Scanner(System.in);
        System.out.println("請(qǐng)輸入學(xué)生人數(shù):");
        int num = scan.nextInt();

        //2.根據(jù)人數(shù)鲫趁,創(chuàng)建指定長(zhǎng)度的數(shù)組 (使用動(dòng)態(tài)初始化)
        int[] scores = new int[num];

        //3. 遍歷數(shù)組斯嚎,通過(guò)控制臺(tái)的方式給每個(gè)數(shù)組元素賦值
        System.out.println("請(qǐng)輸入" + num + "個(gè)成績(jī):");
        for(int i = 0;i < scores.length;i++){
            int score = scan.nextInt();
            scores[i] = score;
        }

        //4. 獲取數(shù)組中元素的最大值
        int maxScore = scores[0];
        for(int i = 1;i < scores.length;i++){
            if(maxScore < scores[i]){
                maxScore = scores[i];
            }
        }

        System.out.println("最高分為:" + maxScore);

        //5. 遍歷數(shù)組,判斷每個(gè)學(xué)生成績(jī)與最高分的差值挨厚,根據(jù)差值堡僻,決定每個(gè)學(xué)生的等級(jí),并輸出
        for(int i = 0;i < scores.length;i++){
            char grade;
            if(scores[i] >= maxScore - 10){
                grade = 'A';
            }else if(scores[i] >= maxScore - 20){
                grade = 'B';
            }else if(scores[i] >= maxScore - 30){
                grade = 'C';
            }else{
                grade = 'D';
            }

            System.out.println("student " + i + " score is " + scores[i] + " grade is " + grade);
        }

5. 多維數(shù)組的使用

5.1 概述

  • Java 語(yǔ)言里提供了支持多維數(shù)組的語(yǔ)法疫剃。
  • 如果說(shuō)可以把一維數(shù)組當(dāng)成幾何中的線性圖形钉疫,那么二維數(shù)組就相當(dāng)于是一個(gè)表格,像右圖Excel中的表格一樣巢价。
  • 對(duì)于二維數(shù)組的理解牲阁,我們可以看成是一維數(shù)組array1又作為另一個(gè)一維數(shù)組array2的元素而存在。其實(shí)壤躲,從數(shù)組底層的運(yùn)行機(jī)制來(lái)看城菊,其實(shí)沒有多維數(shù)組。

5.2 聲明與初始化

5.2.1 聲明

二維數(shù)組聲明的語(yǔ)法格式:

//推薦
元素的數(shù)據(jù)類型[][] 二維數(shù)組的名稱;

//不推薦
元素的數(shù)據(jù)類型  二維數(shù)組名[][];
//不推薦
元素的數(shù)據(jù)類型[]  二維數(shù)組名[];

例如:

public class Test20TwoDimensionalArrayDefine {
    public static void main(String[] args) {
        //存儲(chǔ)多組成績(jī)
        int[][] grades;

        //存儲(chǔ)多組姓名
        String[][] names;
    }
}

面試:

int[] x, y[];
//x是一維數(shù)組柒爵,y是二維數(shù)組

5.2.2 靜態(tài)初始化

格式:

int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};

定義一個(gè)名稱為arr的二維數(shù)組役电,二維數(shù)組中有三個(gè)一維數(shù)組

  • 每一個(gè)一維數(shù)組中具體元素也都已初始化
    • 第一個(gè)一維數(shù)組 arr[0] = {3,8,2};
    • 第二個(gè)一維數(shù)組 arr[1] = {2,7};
    • 第三個(gè)一維數(shù)組 arr[2] = {9,0,1,6};
  • 第三個(gè)一維數(shù)組的長(zhǎng)度表示方式:arr[2].length;
  • 注意特殊寫法情況:int[] x,y[]; x是一維數(shù)組赚爵,y是二維數(shù)組棉胀。
  • 示例:

舉例1:

int[][] arr = {{1,2,3},{4,5,6},{7,8,9,10}};//聲明與初始化必須在一句完成

int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};

int[][] arr;
arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};

arr = new int[3][3]{{1,2,3},{4,5,6},{7,8,9,10}};//錯(cuò)誤,靜態(tài)初始化右邊new 數(shù)據(jù)類型[][]中不能寫數(shù)字

舉例2:

public class TwoDimensionalArrayInitialize {
    public static void main(String[] args) {
        //存儲(chǔ)多組成績(jī)
        int[][] grades = {
                    {89,75,99,100},
                    {88,96,78,63,100,86},
                    {56,63,58},
                    {99,66,77,88}
                };

        //存儲(chǔ)多組姓名
        String[][] names = {
            {"張三","李四", "王五", "趙六"},
            {"劉備","關(guān)羽","張飛","諸葛亮","趙云","馬超"},
            {"曹丕","曹植","曹沖"},
            {"孫權(quán)","周瑜","魯肅","黃蓋"}
        };
    }
}

5.2.3 動(dòng)態(tài)初始化

如果二維數(shù)組的每一個(gè)數(shù)據(jù)冀膝,甚至是每一行的列數(shù)唁奢,需要后期單獨(dú)確定,那么就只能使用動(dòng)態(tài)初始化方式了窝剖。動(dòng)態(tài)初始化方式分為兩種格式:

格式1:規(guī)則二維表:每一行的列數(shù)是相同的

//(1)確定行數(shù)和列數(shù)
元素的數(shù)據(jù)類型[][] 二維數(shù)組名 = new 元素的數(shù)據(jù)類型[m][n];
    //其中麻掸,m:表示這個(gè)二維數(shù)組有多少個(gè)一維數(shù)組〈蜕矗或者說(shuō)一共二維表有幾行
    //其中脊奋,n:表示每一個(gè)一維數(shù)組的元素有多少個(gè)熬北。或者說(shuō)每一行共有一個(gè)單元格

//此時(shí)創(chuàng)建完數(shù)組诚隙,行數(shù)讶隐、列數(shù)確定,而且元素也都有默認(rèn)值

//(2)再為元素賦新值
二維數(shù)組名[行下標(biāo)][列下標(biāo)] = 值;

舉例:

int[][] arr = new int[3][2];
  • 定義了名稱為arr的二維數(shù)組

  • 二維數(shù)組中有3個(gè)一維數(shù)組

  • 每一個(gè)一維數(shù)組中有2個(gè)元素

  • 一維數(shù)組的名稱分別為arr[0], arr[1], arr[2]

  • 給第一個(gè)一維數(shù)組1腳標(biāo)位賦值為78寫法是:arr[0][1] = 78;

格式2:不規(guī)則:每一行的列數(shù)不一樣

//(1)先確定總行數(shù)
元素的數(shù)據(jù)類型[][] 二維數(shù)組名 = new 元素的數(shù)據(jù)類型[總行數(shù)][];

//此時(shí)只是確定了總行數(shù)久又,每一行里面現(xiàn)在是null

//(2)再確定每一行的列數(shù)巫延,創(chuàng)建每一行的一維數(shù)組
二維數(shù)組名[行下標(biāo)] = new 元素的數(shù)據(jù)類型[該行的總列數(shù)];

//此時(shí)已經(jīng)new完的行的元素就有默認(rèn)值了,沒有new的行還是null

//(3)再為元素賦值
二維數(shù)組名[行下標(biāo)][列下標(biāo)] = 值;

舉例:

int[][] arr = new int[3][];
  • 二維數(shù)組中有3個(gè)一維數(shù)組地消。
  • 每個(gè)一維數(shù)組都是默認(rèn)初始化值null (注意:區(qū)別于格式1)
  • 可以對(duì)這個(gè)三個(gè)一維數(shù)組分別進(jìn)行初始化:arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];
  • 注:int[][]arr = new int[][3]; //非法

練習(xí):

/*
 1
 2 2
 3 3 3
 4 4 4 4
 5 5 5 5 5
 */
public class Test25DifferentElementCount {
    public static void main(String[] args){
        //1炉峰、聲明一個(gè)二維數(shù)組,并且確定行數(shù)
        //因?yàn)槊恳恍械牧袛?shù)不同脉执,這里無(wú)法直接確定列數(shù)
        int[][]  arr = new int[5][];

        //2疼阔、確定每一行的列數(shù)
        for(int i=0; i<arr.length; i++){
            /*
            arr[0] 的列數(shù)是1
            arr[1] 的列數(shù)是2
            arr[2] 的列數(shù)是3
            arr[3] 的列數(shù)是4
            arr[4] 的列數(shù)是5
            */
            arr[i] = new int[i+1];
        }

        //3、確定元素的值
        for(int i=0; i<arr.length; i++){
            for(int j=0; j<arr[i].length; j++){
                arr[i][j] = i+1;
            }
        }

        //4半夷、遍歷顯示
        for(int i=0; i<arr.length; i++){
            for(int j=0; j<arr[i].length; j++){
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }

    }
}

小結(jié):

Java中多維數(shù)組不必都是規(guī)則矩陣形式

5.3 使用說(shuō)明

因?yàn)槎S數(shù)組是用來(lái)存儲(chǔ)多組數(shù)據(jù)的竿开,因此要比一維數(shù)組麻煩一些,需要我們搞清楚如下幾個(gè)概念:

  • 二維數(shù)組的長(zhǎng)度/行數(shù):二維數(shù)組名.length
  • 二維數(shù)組的某一行:二維數(shù)組名[行下標(biāo)]玻熙,此時(shí)相當(dāng)于獲取其中一組數(shù)據(jù)否彩。它本質(zhì)上是一個(gè)一維數(shù)組。行下標(biāo)的范圍:[0, 二維數(shù)組名.length-1]嗦随。此時(shí)把二維數(shù)組看成一維數(shù)組的話列荔,元素是行對(duì)象。
  • 某一行的列數(shù):二維數(shù)組名[行下標(biāo)].length枚尼,因?yàn)槎S數(shù)組的每一行是一個(gè)一維數(shù)組贴浙。
  • 某一個(gè)元素:二維數(shù)組名[行下標(biāo)][列下標(biāo)],即先確定行/組署恍,再確定列崎溃。
public class Test22TwoDimensionalArrayUse {
    public static void main(String[] args){
        //存儲(chǔ)3個(gè)小組的學(xué)員的成績(jī),分開存儲(chǔ)盯质,使用二維數(shù)組袁串。
        /*
        int[][] scores1;
        int scores2[][];
        int[] scores3[];*/

        int[][] scores = {
                {85,96,85,75},
                {99,96,74,72,75},
                {52,42,56,75}
        };

        System.out.println(scores);//[[I@15db9742
        System.out.println("一共有" + scores.length +"組成績(jī).");

        //[[:代表二維數(shù)組,I代表元素類型是int
        System.out.println(scores[0]);//[I@6d06d69c
        //[:代表一維數(shù)組呼巷,I代表元素類型是int
        System.out.println(scores[1]);//[I@7852e922
        System.out.println(scores[2]);//[I@4e25154f
        //System.out.println(scores[3]);//ArrayIndexOutOfBoundsException: 3

        System.out.println("第1組有" + scores[0].length +"個(gè)學(xué)員.");
        System.out.println("第2組有" + scores[1].length +"個(gè)學(xué)員.");
        System.out.println("第3組有" + scores[2].length +"個(gè)學(xué)員.");

        System.out.println("第1組的每一個(gè)學(xué)員成績(jī)?nèi)缦拢?);
        //第一行的元素
        System.out.println(scores[0][0]);//85
        System.out.println(scores[0][1]);//96
        System.out.println(scores[0][2]);//85
        System.out.println(scores[0][3]);//75
        //System.out.println(scores[0][4]);//java.lang.ArrayIndexOutOfBoundsException: 4
    }
}

二維數(shù)組的遍歷:

  • 格式:
for(int i=0; i<二維數(shù)組名.length; i++){ //二維數(shù)組對(duì)象.length
    for(int j=0; j<二維數(shù)組名[i].length; j++){//二維數(shù)組行對(duì)象.length
        System.out.print(二維數(shù)組名[i][j]);
    }
    System.out.println();
}
  • 舉例:
public class Test23TwoDimensionalArrayIterate {
    public static void main(String[] args) {
        //存儲(chǔ)3個(gè)小組的學(xué)員的成績(jī)囱修,分開存儲(chǔ),使用二維數(shù)組王悍。
        int[][] scores = {
                {85,96,85,75},
                {99,96,74,72,75},
                {52,42,56,75}
        };

        System.out.println("一共有" + scores.length +"組成績(jī).");
        for (int i = 0; i < scores.length; i++) {
            System.out.print("第" + (i+1) +"組有" + scores[i].length + "個(gè)學(xué)員破镰,成績(jī)?nèi)缦拢?);
            for (int j = 0; j < scores[i].length; j++) {
                System.out.print(scores[i][j]+"\t");
            }
            System.out.println();
        }
    }
}

5.4 內(nèi)存解析

二維數(shù)組本質(zhì)上是元素類型是一維數(shù)組的一維數(shù)組。

        int[][] arr = {
            {1},
            {2,2},
            {3,3,3},
            {4,4,4,4},
            {5,5,5,5,5}
        };
        //1、聲明二維數(shù)組鲜漩,并確定行數(shù)和列數(shù)
        int[][] arr = new int[4][5];
        
        //2源譬、確定元素的值
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length; j++) {
                arr[i][j] = i + 1;
            }
        }
        //1、聲明一個(gè)二維數(shù)組孕似,并且確定行數(shù)
        //因?yàn)槊恳恍械牧袛?shù)不同瓶佳,這里無(wú)法直接確定列數(shù)
        int[][]  arr = new int[5][];
        
        //2、確定每一行的列數(shù)
        for(int i=0; i<arr.length; i++){
            /*
            arr[0] 的列數(shù)是1
            arr[1] 的列數(shù)是2
            arr[2] 的列數(shù)是3
            arr[3] 的列數(shù)是4
            arr[4] 的列數(shù)是5
            */
            arr[i] = new int[i+1];
        }
        
        //3鳞青、確定元素的值
        for(int i=0; i<arr.length; i++){
            for(int j=0; j<arr[i].length; j++){
                arr[i][j] = i+1;
            }
        }

5.6 應(yīng)用舉例

案例1:獲取arr數(shù)組中所有元素的和霸饲。

提示:使用for的嵌套循環(huán)即可。

int[][] arr = {{3,5,8},{12,9},{7,0,6,4}};
int sum = 0;
for(int i = 0;i < arr.length ;i++){
    for(int j = 0; j < arr[i].length;j++){
        sum+=arr[i][j];
    }
}
System.out.println("所有元素的和:"+sum);

案例2:聲明:int[] x,y[]; 在給x,y變量賦值以后臂拓,以下選項(xiàng)允許通過(guò)編譯的是:

聲明:int[] x,y[]; 在給x,y變量賦值以后厚脉,以下選項(xiàng)允許通過(guò)編譯的是: 
a)    x[0] = y;         //no
b)    y[0] = x;         //yes
c)    y[0][0] = x;      //no
d)    x[0][0] = y;      //no
e)    y[0][0] = x[0];   //yes
f)    x = y;            //no

提示:
一維數(shù)組:int[] x  或者int x[]   
二維數(shù)組:int[][] y 或者  int[] y[]  或者 int  y[][]

案例3:使用二維數(shù)組打印一個(gè) 10 行楊輝三角。

提示:

  1. 第一行有 1 個(gè)元素, 第 n 行有 n 個(gè)元素

  2. 每一行的第一個(gè)元素和最后一個(gè)元素都是 1

  3. 從第三行開始, 對(duì)于非第一個(gè)元素和最后一個(gè)元素的元素胶惰。即:

    yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
    
        //1.二維數(shù)組的聲明和初始化(動(dòng)態(tài)初始化)
        int[][] yangHui = new int[10][];
        //2.通過(guò)for循環(huán)給外層數(shù)組元素yangHui[i]初始化
        for(int i = 0;i <yangHui.length;i++){
            yangHui[i] = new int[i+1];
            //3.賦值:每一行的第一個(gè)元素和最后一個(gè)元素都是 1
            yangHui[i][0] = 1;
            yangHui[i][i] = 1;
            //4.賦值:從第三行開始傻工,對(duì)于非第一個(gè)元素和最后一個(gè)元素的元素的賦值
            for (int j = 1; j < i ;j++){
                yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
            }
        }
        for (int i = 0; i < yangHui.length; i++) {
            //System.out.println(Arrays.toString(yangHui[i]));
            for(int j = 0; j < yangHui[i].length;j++){
                System.out.print(yangHui[i][j] + " ");
            }
            System.out.println();
        }

6. 數(shù)組的常見算法

6.1 數(shù)值型數(shù)組特征值統(tǒng)計(jì)

  • 這里的特征值涉及到:平均值、最大值孵滞、最小值中捆、總和等

舉例1:數(shù)組統(tǒng)計(jì):求總和、均值

public class TestArrayElementSum {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //求總和坊饶、均值
        int sum = 0;//因?yàn)?加上任何數(shù)都不影響結(jié)果
        for(int i=0; i<arr.length; i++){
            sum += arr[i];
        }
        double avg = (double)sum/arr.length;

        System.out.println("sum = " + sum);
        System.out.println("avg = " + avg);
    }
}

舉例2:求數(shù)組元素的總乘積

public class TestArrayElementMul {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};

        //求總乘積
        long result = 1;//因?yàn)?乘以任何數(shù)都不影響結(jié)果
        for(int i=0; i<arr.length; i++){
            result *= arr[i];
        }

        System.out.println("result = " + result);
    }
}

舉例3:求數(shù)組元素中偶數(shù)的個(gè)數(shù)

public class TestArrayElementEvenCount {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //統(tǒng)計(jì)偶數(shù)個(gè)數(shù)
        int evenCount = 0;
        for(int i=0; i<arr.length; i++){
            if(arr[i]%2==0){
                evenCount++;
            }
        }

        System.out.println("evenCount = " + evenCount);
    }
}

舉例4:求數(shù)組元素的最大值

public class TestArrayMax {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //找最大值
        int max = arr[0];
        for(int i=1; i<arr.length; i++){//此處i從1開始泄伪,是max不需要與arr[0]再比較一次了
            if(arr[i] > max){
                max = arr[i];
            }
        }

        System.out.println("max = " + max);
    }
}

舉例5:找最值及其第一次出現(xiàn)的下標(biāo):

public class TestMaxIndex {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9};
        //找最大值以及第一個(gè)最大值下標(biāo)
        int max = arr[0];
        int index = 0;
        for(int i=1; i<arr.length; i++){
            if(arr[i] > max){
                max = arr[i];
                index = i;
            }
        }

        System.out.println("max = " + max);
        System.out.println("index = " + index);
    }
}

舉例6:找最值及其所有最值的下標(biāo)

public class Test13AllMaxIndex {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9,9,3};
        //找最大值
        int max = arr[0];
        for(int i=1; i<arr.length; i++){
            if(arr[i] > max){
                max = arr[i];
            }
        }
        System.out.println("最大值是:" + max);
        System.out.print("最大值的下標(biāo)有:");

        //遍歷數(shù)組,看哪些元素和最大值是一樣的
        for(int i=0; i<arr.length; i++){
            if(max == arr[i]){
                System.out.print(i+"\t");
            }
        }
        System.out.println();
    }
}

優(yōu)化

public class Test13AllMaxIndex2 {
    public static void main(String[] args) {
        int[] arr = {4,5,6,1,9,9,3};
        //找最大值
        int max = arr[0];
        String index = "0";
        for(int i=1; i<arr.length; i++){
            if(arr[i] > max){
                max = arr[i];
                index = i + "";
            }else if(arr[i] == max){
                index += "," + i;
            }
        }

        System.out.println("最大值是" + max);
        System.out.println("最大值的下標(biāo)是[" + index+"]");
    }
}

舉例7:輸入一個(gè)整形數(shù)組匿级,數(shù)組里有正數(shù)也有負(fù)數(shù)蟋滴。數(shù)組中連續(xù)的一個(gè)或多個(gè)整數(shù)組成一個(gè)子數(shù)組,每個(gè)子數(shù)組都有一個(gè)和痘绎。求所有子數(shù)組的和的最大值津函。要求時(shí)間復(fù)雜度為O(n)。
例如:輸入的數(shù)組為1, -2, 3, -10, -4, 7, 2, -5孤页,和最大的子數(shù)組為3, 10, -4, 7, 2尔苦,因此輸出為該子數(shù)組的和18。

public class Test5 {
    public static void main(String[] args) {
        int[] arr = new int[]{1, -2, 3, 10, -4, 7, 2, -5};
        int i = getGreatestSum(arr);
        System.out.println(i);
    }
    
    public static int getGreatestSum(int[] arr){
        int greatestSum = 0;
        if(arr == null || arr.length == 0){ //當(dāng)arr為空時(shí)返回null
            return 0;
        }
        int temp = greatestSum;  //將子數(shù)組最大值賦給temp
        for(int i = 0;i < arr.length;i++){ //遍歷arr數(shù)組
            temp += arr[i];    //將arr元素的值加到temp上
            
            if(temp < 0){     //如果temp小于0行施,將temp重新復(fù)制成0
                temp = 0;
            }
            
            if(temp > greatestSum){ //temp總和值 大于 子數(shù)組的值greatestSum 允坚,將temp 賦給 greatestSum
                greatestSum = temp;
            }
        }
        if(greatestSum == 0){   //如果子集合的值為0 (如果arr中都為負(fù)數(shù),選擇最大值返回)
            greatestSum = arr[0];   //將arr數(shù)組的第一個(gè)值賦給 greatestSum
            for(int i = 1;i < arr.length;i++){ //遍歷arr數(shù)組
                if(greatestSum < arr[i]){   //將arr中最大值賦給greatestSum
                    greatestSum = arr[i];
                }
            }
        }
        return greatestSum;
    }
}

6.2 數(shù)組元素的賦值

舉例1:楊輝三角(前面已講過(guò))

舉例2:使用簡(jiǎn)單數(shù)組

(1)創(chuàng)建一個(gè)名為ArrayTest的類悲龟,在main()方法中聲明array1和array2兩個(gè)變量屋讶,他們是int[]類型的數(shù)組冰寻。

(2)使用大括號(hào){}须教,把a(bǔ)rray1初始化為8個(gè)素?cái)?shù):2,3,5,7,11,13,17,19。

(3)顯示array1的內(nèi)容。

(4)賦值array2變量等于array1轻腺,修改array2中的偶索引元素乐疆,使其等于索引值(如array[0]=0,array[2]=2)。打印出array1贬养。 array2 = array1;

思考:array1和array2是什么關(guān)系挤土?

  array1 和 array2 是兩個(gè)變量,共同指向了堆空間中的同一個(gè)數(shù)組误算,則二者的地址值相同

拓展:修改題目仰美,實(shí)現(xiàn)array2對(duì)array1數(shù)組的復(fù)制

舉例3:一個(gè)數(shù)組,讓數(shù)組的每個(gè)元素去除第一個(gè)元素儿礼,得到的商作為被除數(shù)所在位置的新值咖杂。

public class Test3 {
    public static void main(String[] args) {
        int[] arr = new int[]{12,43,65,3,-8,64,2};
        
//      for(int i = 0;i < arr.length;i++){   沒有考慮第一個(gè)元素與第一個(gè)之間的結(jié)果為1,后面的值都是去除以1的蚊夫。
//          arr[i] = arr[i] / arr[0];
//      }
        for(int i = arr.length -1;i >= 0;i--){ //逆序 或者 將第一個(gè)元素賦值給一個(gè)變量诉字,然后用數(shù)組的元素去除以變量
            arr[i] = arr[i] / arr[0];
        }
        //遍歷arr
        for(int i = 0;i < arr.length;i++){
            System.out.print(arr[i] + " ");
        }
    }
}

舉例4:創(chuàng)建一個(gè)長(zhǎng)度為6的int型數(shù)組,要求數(shù)組元素的值都在1-30之間知纷,且是隨機(jī)賦值壤圃。同時(shí),要求元素的值各不相同琅轧。

public class Test4 {
    // 5-67 Math.random() * 63 + 5;
    @Test
    public void test1() {
        int[] arr = new int[6];
        for (int i = 0; i < arr.length; i++) {// [0,1) [0,30) [1,31)
            arr[i] = (int) (Math.random() * 30) + 1;

            boolean flag = false;
            while (true) {
                for (int j = 0; j < i; j++) {
                    if (arr[i] == arr[j]) {
                        flag = true;
                        break;
                    }
                }
                if (flag) {
                    arr[i] = (int) (Math.random() * 30) + 1;
                    flag = false;
                    continue;
                }
                break;
            }
        }

        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
    //更優(yōu)的方法
    @Test
    public void test2(){
        int[] arr = new int[6];
        for (int i = 0; i < arr.length; i++) {// [0,1) [0,30) [1,31)
            arr[i] = (int) (Math.random() * 30) + 1;
            
                for (int j = 0; j < i; j++) {
                    if (arr[i] == arr[j]) {
                        i--;
                        break;
                    }
                }
            }

        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

舉例5:回形數(shù)

從鍵盤輸入一個(gè)整數(shù)(1~20) 伍绳,則以該數(shù)字為矩陣的大小,把1,2,3…n*n 的數(shù)字按照順時(shí)針螺旋的形式填入其中乍桂。

例如: 輸入數(shù)字2墨叛,則程序輸出:
1 2
4 3

輸入數(shù)字3,則程序輸出:
1 2 3
8 9 4
7 6 5
輸入數(shù)字4模蜡, 則程序輸出:
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7

//方式1
public class RectangleTest {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("輸入一個(gè)數(shù)字");
        int len = scanner.nextInt();
        int[][] arr = new int[len][len];
        
        int s = len * len;
        /*
         * k = 1:向右
         * k = 2:向下
         * k = 3:向左
         * k = 4:向上
         */
        int k = 1;
        int i = 0,j = 0;
        for(int m = 1;m <= s;m++){
            if(k == 1){
                if(j < len && arr[i][j] == 0){
                    arr[i][j++] = m;
                }else{
                    k = 2;
                    i++;  
                    j--;
                    m--;
                }
            }else if(k == 2){
                if(i < len && arr[i][j] == 0){
                    arr[i++][j] = m;
                }else{
                    k = 3;
                    i--;
                    j--;
                    m--;
                }
            }else if(k == 3){
                if(j >= 0 && arr[i][j] == 0){
                    arr[i][j--] = m;
                }else{
                    k = 4;
                    i--;
                    j++;
                    m--;
                }
            }else if(k == 4){
                if(i >= 0 && arr[i][j] == 0){
                    arr[i--][j] = m;
                }else{
                    k = 1;
                    i++;
                    j++;
                    m--;
                }
            }
        }
        
        //遍歷
        for(int m = 0;m < arr.length;m++){
            for(int n = 0;n < arr[m].length;n++){
                System.out.print(arr[m][n] + "\t");
            }
            System.out.println();
        }
    }
}
//方式2
/*
    01 02 03 04 05 06 07 
    24 25 26 27 28 29 08 
    23 40 41 42 43 30 09 
    22 39 48 49 44 31 10 
    21 38 47 46 45 32 11 
    20 37 36 35 34 33 12 
    19 18 17 16 15 14 13 
 */
public class RectangleTest1 {

    public static void main(String[] args) {
        int n = 7;
        int[][] arr = new int[n][n];
        
        int count = 0; //要顯示的數(shù)據(jù)
        int maxX = n-1; //x軸的最大下標(biāo)
        int maxY = n-1; //Y軸的最大下標(biāo)
        int minX = 0; //x軸的最小下標(biāo)
        int minY = 0; //Y軸的最小下標(biāo)
        while(minX<=maxX) {
            for(int x=minX;x<=maxX;x++) {
                arr[minY][x] = ++count;
            }
            minY++;
            for(int y=minY;y<=maxY;y++) {
                arr[y][maxX] = ++count;
            }
            maxX--;
            for(int x=maxX;x>=minX;x--) {
                arr[maxY][x] = ++count;
            }
            maxY--;
            for(int y=maxY;y>=minY;y--) {
                arr[y][minX] = ++count;
            }
            minX++;
        }
        
        
        for(int i=0;i<arr.length;i++) {
            for(int j=0;j<arr.length;j++) {
                String space = (arr[i][j]+"").length()==1 ? "0":"";
                System.out.print(space+arr[i][j]+" ");
            }
            System.out.println();
        }
    }
}

6.3 數(shù)組的元素查找

1漠趁、順序查找

順序查找:挨個(gè)查看

要求:對(duì)數(shù)組元素的順序沒要求

public class TestArrayOrderSearch {
    //查找value第一次在數(shù)組中出現(xiàn)的index
    public static void main(String[] args){
        int[] arr = {4,5,6,1,9};
        int value = 1;
        int index = -1;

        for(int i=0; i<arr.length; i++){
            if(arr[i] == value){
                index = i;
                break;
            }
        }

        if(index==-1){
            System.out.println(value + "不存在");
        }else{
            System.out.println(value + "的下標(biāo)是" + index);
        }
    }
}

2、二分查找

//二分法查找:要求此數(shù)組必須是有序的忍疾。
int[] arr3 = new int[]{-99,-54,-2,0,2,33,43,256,999};
boolean isFlag = true;
int number = 256;
//int number = 25;
int head = 0;//首索引位置
int end = arr3.length - 1;//尾索引位置
while(head <= end){
    int middle = (head + end) / 2;
    if(arr3[middle] == number){
        System.out.println("找到指定的元素闯传,索引為:" + middle);
        isFlag = false;
        break;
    }else if(arr3[middle] > number){
        end = middle - 1;
    }else{//arr3[middle] < number
        head = middle + 1;
    }
}

if(isFlag){
    System.out.println("未找打指定的元素");
}

6.4 數(shù)組元素的反轉(zhuǎn)

實(shí)現(xiàn)思想:數(shù)組對(duì)稱位置的元素互換。

public class TestArrayReverse1 {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        System.out.println("反轉(zhuǎn)之前:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

        //反轉(zhuǎn)
         /*
        思路:首尾對(duì)應(yīng)位置的元素交換
        (1)確定交換幾次
           次數(shù) = 數(shù)組.length / 2
        (2)誰(shuí)和誰(shuí)交換
        for(int i=0; i<次數(shù); i++){
             int temp = arr[i];
             arr[i] = arr[arr.length-1-i];
             arr[arr.length-1-i] = temp;
        }
         */
        for(int i=0; i<arr.length/2; i++){
            int temp = arr[i];
            arr[i] = arr[arr.length-1-i];
            arr[arr.length-1-i] = temp;
        }

        System.out.println("反轉(zhuǎn)之后:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

}

public class TestArrayReverse2 {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        System.out.println("反轉(zhuǎn)之前:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

        //反轉(zhuǎn)
        //左右對(duì)稱位置交換
        for(int left=0,right=arr.length-1; left<right; left++,right--){
            //首  與  尾交換
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
        }

        System.out.println("反轉(zhuǎn)之后:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

6.5 數(shù)組元素排序

6.5.1 算法概述

  • 定義
    • 排序:假設(shè)含有n個(gè)記錄的序列為{R1卤妒,R2甥绿,...,Rn},其相應(yīng)的關(guān)鍵字序列為{K1,K2则披,...,Kn}共缕。將這些記錄重新排序?yàn)閧Ri1,Ri2,...,Rin},使得相應(yīng)的關(guān)鍵字值滿足條Ki1<=Ki2<=...<=Kin,這樣的一種操作稱為排序。
    • 通常來(lái)說(shuō)士复,排序的目的是快速查找图谷。
  • 算法的5大特征:

說(shuō)明:滿足確定性的算法也稱為:確定性算法◆婊睿現(xiàn)在人們也關(guān)注更廣泛的概念,例如考慮各種非確定性的算法便贵,如并行算法菠镇、概率算法等。另外承璃,人們也關(guān)注并不要求終止的計(jì)算描述利耍,這種描述有時(shí)被稱為過(guò)程(procedure)。

  • 衡量排序算法的優(yōu)劣:

    • 時(shí)間復(fù)雜度:分析關(guān)鍵字的比較次數(shù)和記錄的移動(dòng)次數(shù)

      • 常見的算法時(shí)間復(fù)雜度由小到大依次為:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
    一個(gè)算法執(zhí)行所耗費(fèi)的時(shí)間盔粹,從理論上是不能算出來(lái)的隘梨,必須上機(jī)運(yùn)行測(cè)試才能知道。但我們不可能也沒有必要對(duì)每個(gè)算法都上機(jī)測(cè)試舷嗡,只需知道哪個(gè)算法花費(fèi)的時(shí)間多出嘹,哪個(gè)算法花費(fèi)的時(shí)間少就可以了。
    
    并且一個(gè)算法花費(fèi)的時(shí)間與算法中語(yǔ)句的執(zhí)行次數(shù)成正比例咬崔,哪個(gè)算法中語(yǔ)句執(zhí)行次數(shù)多税稼,它花費(fèi)時(shí)間就多。一個(gè)算法中的語(yǔ)句執(zhí)行次數(shù)稱為語(yǔ)句頻度或時(shí)間頻度垮斯。記為T(n)郎仆。n稱為問題的規(guī)模,當(dāng)n不斷變化時(shí)兜蠕,時(shí)間頻度T(n)也會(huì)不斷變化扰肌。但有時(shí)我們想知道它變化時(shí)呈現(xiàn)什么規(guī)律。為此熊杨,我們引入時(shí)間復(fù)雜度概念曙旭。 
    
    一般情況下,算法中基本操作重復(fù)執(zhí)行的次數(shù)是問題規(guī)模n的某個(gè)函數(shù)晶府,用T(n)表示桂躏,若有某個(gè)輔助函數(shù)f(n),使得當(dāng)n趨近于無(wú)窮大時(shí),T(n)/f(n)的極限值為不等于零的常數(shù)川陆,則稱f(n)是T(n)的同數(shù)量級(jí)函數(shù)剂习。記作T(n)=O(f(n)),稱O(f(n)) 為算法的漸進(jìn)時(shí)間復(fù)雜度,簡(jiǎn)稱時(shí)間復(fù)雜度较沪。
  • 空間復(fù)雜度:分析排序算法中需要多少輔助內(nèi)存

    類似于時(shí)間復(fù)雜度的討論鳞绕,一個(gè)算法的空間復(fù)雜度(Space Complexity)S(n)定義為該算法所耗費(fèi)的存儲(chǔ)空間,它也是問題規(guī)模n的函數(shù)尸曼。
    
  • 穩(wěn)定性:若兩個(gè)記錄A和B的關(guān)鍵字值相等们何,但排序后A、B的先后次序保持不變控轿,則稱這種排序算法是穩(wěn)定的冤竹。

6.5.2 排序算法概述

  • 排序算法分類:內(nèi)部排序和外部排序

    • 內(nèi)部排序:整個(gè)排序過(guò)程不需要借助于外部存儲(chǔ)器(如磁盤等)拂封,所有排序操作都在內(nèi)存中完成。
    • 外部排序:參與排序的數(shù)據(jù)非常多贴见,數(shù)據(jù)量非常大烘苹,計(jì)算機(jī)無(wú)法把整個(gè)排序過(guò)程放在內(nèi)存中完成躲株,必須借助于外部存儲(chǔ)器(如磁盤)片部。外部排序最常見的是多路歸并排序∷ǎ可以認(rèn)為外部排序是由多次內(nèi)部排序組成档悠。
  • 十大內(nèi)部排序算法

數(shù)組的排序算法很多,實(shí)現(xiàn)方式各不相同望浩,時(shí)間復(fù)雜度辖所、空間復(fù)雜度、穩(wěn)定性也各不相同:

6.5.3 冒泡排序

介紹:

Java中的經(jīng)典算法之冒泡排序(Bubble Sort)磨德。冒泡排序的原理非常簡(jiǎn)單缘回,它重復(fù)地走訪過(guò)要排序的數(shù)列,一次比較兩個(gè)元素典挑,如果他們的順序錯(cuò)誤就把他們交換過(guò)來(lái)酥宴。

排序思想:

  1. 比較相鄰的元素。如果第一個(gè)比第二個(gè)大(升序)您觉,就交換他們兩個(gè)拙寡。

  2. 對(duì)每一對(duì)相鄰元素作同樣的工作,從開始第一對(duì)到結(jié)尾的最后一對(duì)琳水。這步做完后肆糕,最后的元素會(huì)是最大的數(shù)。

  3. 針對(duì)所有的元素重復(fù)以上的步驟在孝,除了最后一個(gè)诚啃。

  4. 持續(xù)每次對(duì)越來(lái)越少的元素重復(fù)上面的步驟,直到?jīng)]有任何一對(duì)數(shù)字需要比較為止私沮。

動(dòng)態(tài)演示:https://visualgo.net/zh/sorting

/*
1绍申、冒泡排序(最經(jīng)典)
思想:每一次比較“相鄰(位置相鄰)”元素,如果它們不符合目標(biāo)順序(例如:從小到大)顾彰,
     就交換它們极阅,經(jīng)過(guò)多輪比較,最終實(shí)現(xiàn)排序涨享。
     (例如:從小到大)   每一輪可以把最大的沉底筋搏,或最小的冒頂。
     
過(guò)程:arr{6,9,2,9,1}  目標(biāo):從小到大

第一輪:
    第1次厕隧,arr[0]與arr[1]奔脐,6>9不成立俄周,滿足目標(biāo)要求,不交換
    第2次髓迎,arr[1]與arr[2]峦朗,9>2成立,不滿足目標(biāo)要求排龄,交換arr[1]與arr[2] {6,2,9,9,1}
    第3次波势,arr[2]與arr[3],9>9不成立橄维,滿足目標(biāo)要求尺铣,不交換
    第4次,arr[3]與arr[4]争舞,9>1成立凛忿,不滿足目標(biāo)要求,交換arr[3]與arr[4] {6,2,9,1,9}
    第一輪所有元素{6,9,2,9,1}已經(jīng)都參與了比較竞川,結(jié)束店溢。
    第一輪的結(jié)果:第“一”最大值9沉底(本次是后面的9沉底),即到{6,2,9,1,9}元素的最右邊

第二輪:
    第1次委乌,arr[0]與arr[1]床牧,6>2成立,不滿足目標(biāo)要求福澡,交換arr[0]與arr[1] {2,6,9,1,9}
    第2次叠赦,arr[1]與arr[2],6>9不成立革砸,滿足目標(biāo)要求除秀,不交換
    第3次:arr[2]與arr[3],9>1成立算利,不滿足目標(biāo)要求册踩,交換arr[2]與arr[3] {2,6,1,9,9}
    第二輪未排序的所有元素 {6,2,9,1}已經(jīng)都參與了比較,結(jié)束效拭。
    第二輪的結(jié)果:第“二”最大值9沉底(本次是前面的9沉底)暂吉,即到{2,6,1,9}元素的最右邊
第三輪:
    第1次,arr[0]與arr[1]缎患,2>6不成立慕的,滿足目標(biāo)要求,不交換
    第2次挤渔,arr[1]與arr[2]肮街,6>1成立,不滿足目標(biāo)要求判导,交換arr[1]與arr[2] {2,1,6,9,9}
    第三輪未排序的所有元素{2,6,1}已經(jīng)都參與了比較嫉父,結(jié)束沛硅。
    第三輪的結(jié)果:第三最大值6沉底,即到 {2,1,6}元素的最右邊
第四輪:
    第1次绕辖,arr[0]與arr[1]摇肌,2>1成立,不滿足目標(biāo)要求仪际,交換arr[0]與arr[1] {1,2,6,9,9}
    第四輪未排序的所有元素{2,1}已經(jīng)都參與了比較围小,結(jié)束。
    第四輪的結(jié)果:第四最大值2沉底弟头,即到{1,2}元素的最右邊

*/
public class Test19BubbleSort{
    public static void main(String[] args){
        int[] arr = {6,9,2,9,1};

        //目標(biāo):從小到大
        //冒泡排序的輪數(shù) = 元素的總個(gè)數(shù) - 1
        //輪數(shù)是多輪吩抓,每一輪比較的次數(shù)是多次涉茧,需要用到雙重循環(huán)赴恨,即循環(huán)嵌套
        //外循環(huán)控制 輪數(shù),內(nèi)循環(huán)控制每一輪的比較次數(shù)和過(guò)程
        for(int i=1; i<arr.length; i++){ //循環(huán)次數(shù)是arr.length-1次/輪
            /*
            假設(shè)arr.length=5
            i=1,第1輪伴栓,比較4次
                arr[0]與arr[1]
                arr[1]與arr[2]
                arr[2]與arr[3]
                arr[3]與arr[4]
                
                arr[j]與arr[j+1]伦连,int j=0;j<4; j++
                
            i=2,第2輪,比較3次
                arr[0]與arr[1]
                arr[1]與arr[2]
                arr[2]與arr[3]
                
                arr[j]與arr[j+1]钳垮,int j=0;j<3; j++
                
            i=3,第3輪惑淳,比較2次
                arr[0]與arr[1]
                arr[1]與arr[2]
                
                arr[j]與arr[j+1],int j=0;j<2; j++
            i=4,第4輪饺窿,比較1次
                arr[0]與arr[1]
            
                arr[j]與arr[j+1]歧焦,int j=0;j<1; j++
                
                int j=0; j<arr.length-i; j++
            */
            for(int j=0; j<arr.length-i; j++){
                //希望的是arr[j] < arr[j+1]
                if(arr[j] > arr[j+1]){
                    //交換arr[j]與arr[j+1]
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }

        //完成排序,遍歷結(jié)果
        for(int i=0; i<arr.length; i++){
            System.out.print(arr[i]+"  ");
        }
    }
}

冒泡排序優(yōu)化

/*
思考:冒泡排序是否可以優(yōu)化
*/
class Test19BubbleSort2{
    public static void main(String[] args){
        int[] arr = {1,3,5,7,9};
        
        //從小到大排序
        //int lun = 0;//聲明lun變量肚医,統(tǒng)計(jì)比較幾輪
        //int count = 0;//聲明count變量绢馍,統(tǒng)計(jì)比較的次數(shù)
        for(int i=1; i<arr.length; i++){ 
            //lun++;
            boolean flag = true;//假設(shè)數(shù)組已經(jīng)是有序的
            for(int j=0; j<arr.length-i; j++){
                //count++;
                //希望的是arr[j] < arr[j+1]
                if(arr[j] > arr[j+1]){
                    //交換arr[j]與arr[j+1]
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    
                    flag = false;//如果元素發(fā)生了交換,那么說(shuō)明數(shù)組還沒有排好序
                }
            }
            if(flag){
                break;
            }
        }
        
        //System.out.println("一共比較了" + lun +"輪");
        //System.out.println("一共比較了" + count +"次");
        
        //完成排序肠套,遍歷結(jié)果
        for(int i=0; i<arr.length; i++){
            System.out.print(arr[i]+"  ");
        }
    }
}

6.5.4 快速排序

介紹:快速排序通常明顯比同為O(nlogn)的其他算法更快舰涌,因此常被采用,而且快排采用了分治法的思想你稚,所以在很多筆試面試中能經(jīng)炒砂遥看到快排的影子〉罄担可見掌握快排的重要性搁痛。

快速排序(Quick Sort)由圖靈獎(jiǎng)獲得者Tony Hoare發(fā)明,被列為20世紀(jì)十大算法之一宇弛,是迄今為止所有內(nèi)排序算法中速度最快的一種鸡典。冒泡排序的升級(jí)版,交換排序的一種涯肩〗文疲快速排序的時(shí)間復(fù)雜度為O(nlog(n))巢钓。

排序思想:

  1. 從數(shù)列中挑出一個(gè)元素,稱為"基準(zhǔn)"(pivot)疗垛,

  2. 重新排序數(shù)列症汹,所有元素比基準(zhǔn)值小的擺放在基準(zhǔn)前面,所有元素比基準(zhǔn)值大的擺在基準(zhǔn)的后面(相同的數(shù)可以到任一邊)贷腕。在這個(gè)分區(qū)結(jié)束之后背镇,該基準(zhǔn)就處于數(shù)列的中間位置。這個(gè)稱為分區(qū)(partition)操作泽裳。

  3. 遞歸地(recursive)把小于基準(zhǔn)值元素的子數(shù)列和大于基準(zhǔn)值元素的子數(shù)列排序瞒斩。

  4. 遞歸的最底部情形,是數(shù)列的大小是零或一涮总,也就是永遠(yuǎn)都已經(jīng)被排序好了胸囱。雖然一直遞歸下去,但是這個(gè)算法總會(huì)結(jié)束瀑梗,因?yàn)樵诿看蔚牡╥teration)中烹笔,它至少會(huì)把一個(gè)元素?cái)[到它最后的位置去。

動(dòng)態(tài)演示:https://visualgo.net/zh/sorting

圖示1:

圖示2:

public class quickSort {
    public static void main(String[] args) {
        int[] arr = {-9,78,0,23,-567,70};
        quickSort(arr,0,arr.length-1);
        System.out.println("arr="+ Arrays.toString(arr));
    }
    public static void quickSort(int[] arr,int left,int right){
        int l = left; //左下標(biāo)
        int r = right; //右下標(biāo)
        int temp = 0; //臨時(shí)變量抛丽,交換時(shí)使用
        //pivot 中軸值
        int pivot = arr[(left + right)/2];
        //while 循環(huán)的目的谤职,是讓比pivot 值小的放到左邊
        //比 pivot 值放到右邊
        while(l < r){ //
            //在pivot 的左邊一直找,找到大于等于 pivot 值亿鲜,才退出
            while( arr[l] < pivot){
                l += 1;
            }
            //在pivot 的右邊一直找允蜈,找到小于等于 pivot 值,才退出
            while(arr[r] > pivot){
                r -= 1;
            }
            //如果l >= r 說(shuō)明 pivot 的左右兩邊的值蒿柳,已經(jīng)按照
            // 左邊全部是小于等于pivot 的值饶套,右邊全部大于等于pivot的值
            if(l >= r){
                break;
            }
            //交換
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
            //如果交換完后,發(fā)現(xiàn)這個(gè) arr[l] == pivot 值相等 r--其馏, 前移
            if(arr[l] == pivot){
                r -= 1;
            }
            //如果交換完后凤跑,發(fā)現(xiàn)這個(gè) arr[r] == pivot 值相等 l++, 后移
            if(arr[l] == pivot){
                l += 1;
            }
        }

        //如果 l == r,必須 l++,r--,否則出現(xiàn)棧溢出
        if(l == r){
            l += 1;
            r -= 1;
        }
        //向左遞歸
        if(left < r){
            quickSort(arr,left,r);
        }
        //向右遞歸
        if(right > l){
            quickSort(arr,l,right);
        }
    }

}

6.5.5 內(nèi)部排序性能比較與選擇

  • 性能比較

    • 從平均時(shí)間而言:快速排序最佳叛复。但在最壞情況下時(shí)間性能不如堆排序和歸并排序仔引。
    • 從算法簡(jiǎn)單性看:由于直接選擇排序、直接插入排序和冒泡排序的算法比較簡(jiǎn)單褐奥,將其認(rèn)為是簡(jiǎn)單算法咖耘。對(duì)于Shell排序、堆排序撬码、快速排序和歸并排序算法儿倒,其算法比較復(fù)雜,認(rèn)為是復(fù)雜排序。
    • 從穩(wěn)定性看:直接插入排序夫否、冒泡排序和歸并排序時(shí)穩(wěn)定的彻犁;而直接選擇排序、快速排序凰慈、 Shell排序和堆排序是不穩(wěn)定排序
    • 從待排序的記錄數(shù)n的大小看汞幢,n較小時(shí),宜采用簡(jiǎn)單排序微谓;而n較大時(shí)宜采用改進(jìn)排序渊鞋。
  • 選擇

    • 若n較小(如n≤50)鼻种,可采用直接插入或直接選擇排序。
      當(dāng)記錄規(guī)模較小時(shí)泉沾,直接插入排序較好尝丐;否則因?yàn)橹苯舆x擇移動(dòng)的記錄數(shù)少于直接插入歹茶,應(yīng)選直接選擇排序?yàn)橐恕?/li>
    • 若文件初始狀態(tài)基本有序(指正序)贫堰,則應(yīng)選用直接插入缕溉、冒泡或隨機(jī)的快速排序?yàn)橐耍?/li>
    • 若n較大,則應(yīng)采用時(shí)間復(fù)雜度為O(nlgn)的排序方法:快速排序哼绑、堆排序或歸并排序岩馍。

5. Arrays工具類的使用

java.util.Arrays類即為操作數(shù)組的工具類碉咆,包含了用來(lái)操作數(shù)組(比如排序和搜索)的各種方法抖韩。

舉例:java.util.Arrays類的sort()方法提供了數(shù)組元素排序功能:

import java.util.Arrays;
public class SortTest {
    public static void main(String[] args) {
        int [] numbers = {5,900,1,5,77,30,64,700};
        Arrays.sort(numbers);
        for(int i = 0; i < numbers.length; i++){
            System.out.println(numbers[i]);
        }
    }
}

6. 數(shù)組中的常見異常

6.1 數(shù)組角標(biāo)越界異常

當(dāng)訪問數(shù)組元素時(shí),下標(biāo)指定超出[0, 數(shù)組名.length-1]的范圍時(shí)疫铜,就會(huì)報(bào)數(shù)組下標(biāo)越界異常:ArrayIndexOutOfBoundsException茂浮。

public class TestArrayIndexOutOfBoundsException {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
       // System.out.println("最后一個(gè)元素:" + arr[3]);//錯(cuò)誤,下標(biāo)越界
      //  System.out.println("最后一個(gè)元素:" + arr[arr.length]);//錯(cuò)誤壳咕,下標(biāo)越界
        System.out.println("最后一個(gè)元素:" + arr[arr.length-1]);//對(duì)
    }
}

創(chuàng)建數(shù)組席揽,賦值3個(gè)元素,數(shù)組的索引就是0谓厘,1幌羞,2,沒有3索引竟稳,因此我們不能訪問數(shù)組中不存在的索引属桦,程序運(yùn)行后,將會(huì)拋出 ArrayIndexOutOfBoundsException 數(shù)組越界異常他爸。在開發(fā)中聂宾,數(shù)組的越界異常是不能出現(xiàn)的,一旦出現(xiàn)了诊笤,就必須要修改我們編寫的代碼系谐。

6.2 空指針異常

觀察一下代碼,運(yùn)行后會(huì)出現(xiàn)什么結(jié)果讨跟。

public class TestNullPointerException {
    public static void main(String[] args) {
        //定義數(shù)組
        int[][] arr = new int[3][];

        System.out.println(arr[0][0]);//NullPointerException
    }
}

因?yàn)榇藭r(shí)數(shù)組的每一行還未分配具體存儲(chǔ)元素的空間纪他,此時(shí)arr[0]是null鄙煤,此時(shí)訪問arr[0][0]會(huì)拋出NullPointerException 空指針異常。

空指針異常在內(nèi)存圖中的表現(xiàn)

小結(jié):空指針異常情況

        //舉例一:
//      int[] arr1 = new int[10];
//      arr1 = null;
//      System.out.println(arr1[9]);
        
        //舉例二:
//      int[][] arr2 = new int[5][];
//      //arr2[3] = new int[10];
//      System.out.println(arr2[3][3]);
        
        //舉例三:
        String[] arr3 = new String[10];
        System.out.println(arr3[2].toString());
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末茶袒,一起剝皮案震驚了整個(gè)濱河市馆类,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弹谁,老刑警劉巖乾巧,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異预愤,居然都是意外死亡沟于,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門植康,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)旷太,“玉大人,你說(shuō)我怎么就攤上這事销睁」╄担” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵冻记,是天一觀的道長(zhǎng)睡毒。 經(jīng)常有香客問我,道長(zhǎng)冗栗,這世上最難降的妖魔是什么演顾? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮隅居,結(jié)果婚禮上钠至,老公的妹妹穿的比我還像新娘。我一直安慰自己胎源,他們只是感情好棉钧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涕蚤,像睡著了一般宪卿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赞季,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天愧捕,我揣著相機(jī)與錄音,去河邊找鬼申钩。 笑死次绘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邮偎,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼管跺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了禾进?” 一聲冷哼從身側(cè)響起豁跑,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泻云,沒想到半個(gè)月后艇拍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宠纯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年卸夕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婆瓜。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡快集,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出廉白,到底是詐尸還是另有隱情个初,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布猴蹂,位于F島的核電站院溺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏晕讲。R本人自食惡果不足惜覆获,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瓢省。 院中可真熱鬧,春花似錦痊班、人聲如沸勤婚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)馒胆。三九已至,卻和暖如春凝果,著一層夾襖步出監(jiān)牢的瞬間祝迂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工器净, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留型雳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像纠俭,于是被迫代替她去往敵國(guó)和親沿量。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容