JAVA編程講義數(shù)組

      網(wǎng)友投稿 901 2022-05-29

      在程序開發(fā)過程中,有時候需要存儲大量的同類型數(shù)據(jù)。例如,存儲一個班級50名學(xué)生的姓名,這時需要定義50個變量來保存姓名數(shù)據(jù),但這種做法太繁瑣了。那么,如何解決這類問題呢?Java語言提供了數(shù)組結(jié)構(gòu),它類似于一個容器,可以批量存儲相同數(shù)據(jù)類型的元素。因此,對于前述學(xué)生成績統(tǒng)計(jì)問題,我們只需要定義一個長度為50的字符串?dāng)?shù)組就可以解決。本章將對數(shù)組的基本概念、定義方式、初始化以及使用等內(nèi)容展開講解。

      4.1 一維數(shù)組

      一維數(shù)組的邏輯結(jié)構(gòu)是線性表,它是最簡單的數(shù)組。使用一維數(shù)組時,要先定義,然后做初始化,最后才能使用。本節(jié)為大家詳細(xì)講解一維數(shù)組的具體用法。

      4.1.1 一維數(shù)組的創(chuàng)建

      在Java中使用數(shù)組,一般需要3個步驟:聲明數(shù)組、創(chuàng)建數(shù)組對象空間、為數(shù)組元素賦值。其中,聲明數(shù)組和創(chuàng)建數(shù)組對象空間的語法如下:

      數(shù)據(jù)類型[] 數(shù)組名; // 聲明一維數(shù)組,這種是推薦的寫法

      數(shù)據(jù)類型 數(shù)組名[]; // 聲明一維數(shù)組的第二種寫法

      數(shù)組名 = new 數(shù)據(jù)類型[數(shù)組元素個數(shù)]; // 為數(shù)組對象分配內(nèi)存空間

      在上面一維數(shù)組的聲明語句中,“數(shù)據(jù)類型”可以是Java語言中的任意數(shù)據(jù)類型,包括簡單類型和對象類型。“數(shù)組名”是用來訪問數(shù)組的標(biāo)識,作用與變量名類似,在程序中可以通過“數(shù)組名”訪問數(shù)組中的元素,“數(shù)組名”的命名規(guī)則與變量的命名規(guī)則相同。另外,“[ ]”是定義數(shù)組類型的符號,聲明數(shù)組時必須要有這個符號,這個符號可以放在數(shù)據(jù)類型后面,也可以放在數(shù)組名后面。

      數(shù)組聲明之后,就需要為數(shù)組對象分配一個固定長度的存儲空間。在為數(shù)組分配內(nèi)存空間的時候,需要使用new運(yùn)算符。通過new運(yùn)算符可以告訴編譯器聲明的數(shù)組存儲什么類型的數(shù)據(jù),以及數(shù)組要存儲的元素個數(shù)。數(shù)組一旦創(chuàng)建長度就固定了,不能再次改變。

      針對數(shù)組的聲明和內(nèi)存分配,舉例說明如下:

      int[] nums; // 聲明數(shù)組名為nums的整形數(shù)組

      nums = new int[10]; // 為nums數(shù)組分配10個存儲整數(shù)的內(nèi)存空間

      在這例子中,第1行代碼只是聲明了一個整數(shù)類型的數(shù)組變量nums,但是這個變量沒有指向任何一個數(shù)組對象空間,聲明的數(shù)組變量是在JVM的棧內(nèi)存中分配空間。第2行代碼先通過new運(yùn)算符創(chuàng)建了一個長度為10的整型數(shù)組空間,創(chuàng)建的數(shù)組空間是在JVM的堆內(nèi)存中分配的。接著把數(shù)組對象賦值給nums,也就是將數(shù)組對象的地址存儲到了nums變量中。此時,nums變量就指了這個數(shù)據(jù)對象上,因此通過nums可以訪問到數(shù)組對象空間中的每一個元素。對于數(shù)組聲明和數(shù)組對象內(nèi)存分配,可以參考圖4.1。

      (a)只聲明數(shù)組變量但未指向數(shù)組對象空間 (b)聲明數(shù)組并指向數(shù)組對象空間

      圖4.1 數(shù)組聲明和內(nèi)存分配

      圖4.1中,左圖聲明了一個整型數(shù)組變量nums,這個變量對應(yīng)一個棧內(nèi)存的空間。因?yàn)閚ums沒有指向數(shù)組對象,所以nums存儲的內(nèi)容是null。右圖中在堆內(nèi)存中創(chuàng)建了一個連續(xù)的長度為10的整型數(shù)組對象空間,數(shù)組對象的首地址是0x8A21。右圖中聲明的數(shù)組變量nums存儲了數(shù)組對象的首地址。因此nums變量指向了這個數(shù)組對象,與這個數(shù)組對象有了引用關(guān)聯(lián)。通過nums變量可以用下標(biāo)索引的方式,訪問數(shù)組中的每個元素。

      另外,也可以使用一條語句完成數(shù)組的聲明和內(nèi)存分配,語法說明如下:

      數(shù)據(jù)類型[] 數(shù)組名 = new 數(shù)據(jù)類型[數(shù)組元素個數(shù)]

      使用這種方式會在定義數(shù)組的同時為數(shù)組分配內(nèi)存空間,舉例說明如下:

      int[] nums = new int[10]; // 聲明數(shù)組的同時為數(shù)組分配內(nèi)存空間

      在這行代碼中,等號左邊的nums是聲明的數(shù)組變量,它指向了右邊使用new運(yùn)算符創(chuàng)建的數(shù)組對象。

      知識點(diǎn)撥:在Java中,數(shù)組對象被創(chuàng)建之后,數(shù)組中的元素都具有一個初始的默認(rèn)值。整型數(shù)組的元素默認(rèn)值是0。浮點(diǎn)類型數(shù)組的元素默認(rèn)值是0.0。布爾類型數(shù)組的元素默認(rèn)值是false。字符串和對象等引用類型數(shù)組的元素默認(rèn)值都是null。

      4.1.2 數(shù)組元素的分配

      在創(chuàng)建數(shù)組對象之后,就可以存儲數(shù)據(jù)到數(shù)組元素空間中,進(jìn)行數(shù)組元素的分配,也就是為數(shù)組元素賦值。為數(shù)組元素賦值的方式有3種:靜態(tài)初始化、動態(tài)初始化、通過數(shù)組下標(biāo)為數(shù)組賦值。

      1.靜態(tài)初始化

      靜態(tài)初始化就是在聲明數(shù)組時,由開發(fā)者顯式指定每個數(shù)組元素的初始值,初始值的類型要和定義數(shù)組的類型一致。根據(jù)這些初始值,系統(tǒng)會自動創(chuàng)建對應(yīng)長度的數(shù)組空間,用于存儲每個數(shù)組元素的數(shù)據(jù)。靜態(tài)初始化語法如下:

      數(shù)據(jù)類型[] 數(shù)組名 = {數(shù)據(jù)1,數(shù)據(jù)2,數(shù)據(jù)3,…,數(shù)據(jù)n}; // 靜態(tài)初始化,第1種方式

      數(shù)據(jù)類型[] 數(shù)組名;

      數(shù)組名 = new 數(shù)據(jù)類型[]{數(shù)據(jù)1,數(shù)據(jù)2,數(shù)據(jù)3,…,數(shù)據(jù)n}; // 靜態(tài)初始化,第2種方式

      第1種靜態(tài)初始化的方式,需要在聲明數(shù)組的同時進(jìn)行數(shù)據(jù)初始化,初始化的數(shù)據(jù)要寫在大括號中,并以逗號分隔。第2種靜態(tài)初始化的方式可以先聲明數(shù)組變量,然后使用new運(yùn)算符進(jìn)行數(shù)組元素的初始化。另外,第2種方式中,右邊表達(dá)式中的“[ ]”不允許寫數(shù)組長度,否則會發(fā)生語法錯誤。

      靜態(tài)初始化示例代碼如下:

      int[] nums = {10,20,30,40,50}; // 聲明數(shù)組并進(jìn)行數(shù)組靜態(tài)初始化

      String[] names; // 聲明數(shù)組變量

      names = new String[]{"唐僧","孫悟空","豬八戒","沙和尚"}; // 進(jìn)行靜態(tài)初始化

      2.動態(tài)初始化

      進(jìn)行數(shù)組動態(tài)初始化時,開發(fā)者只需要指定數(shù)組長度,然后由系統(tǒng)自動為數(shù)組元素分配初始值。動態(tài)初始化的語法格式如下:

      數(shù)據(jù)類型[] 數(shù)組名 = new 數(shù)據(jù)類型[數(shù)組長度];

      在進(jìn)行動態(tài)初始化后,程序會根據(jù)指定的數(shù)組長度,創(chuàng)建對應(yīng)長度的數(shù)組元素空間,并為每個數(shù)組元素空間設(shè)置初始值。

      動態(tài)初始化的示例代碼如下:

      int[] nums = new int[5]; // 創(chuàng)建長度為5的整型數(shù)組,數(shù)組元素的初始值都是0

      String[] names = new String[3]; // 創(chuàng)建長度為3的字符串?dāng)?shù)組,數(shù)組元素的初始值都為null

      3.通過數(shù)組下標(biāo)為數(shù)組賦值

      在數(shù)組創(chuàng)建之后,可以使用數(shù)組名結(jié)合數(shù)組下標(biāo)的方式,為數(shù)組空間中的每個元素賦值。使用數(shù)組下標(biāo)賦值的語法格式如下:

      數(shù)據(jù)類型[] 數(shù)組名 = new 數(shù)據(jù)類型[數(shù)組長度];

      數(shù)組名[下標(biāo)1] = 數(shù)值1;

      數(shù)組名[下標(biāo)2] = 數(shù)值2;

      數(shù)組名[數(shù)組長度-1] = 數(shù)值n;

      在通過數(shù)組下標(biāo)為數(shù)組元素賦值的時候,數(shù)組下標(biāo)的取值范圍從0到數(shù)組長度減1為止。下標(biāo)超出這個范圍,會發(fā)生“ArrayIndexOutOfBoundsException”數(shù)組下標(biāo)越界的異常。

      通過數(shù)組下標(biāo)為元素賦值的代碼示例如下:

      String[] names = new String[4]; // 聲明長度為4的字符串?dāng)?shù)組

      names[0] = "唐僧"; // 通過下標(biāo)為每個數(shù)組元素賦值

      names[1] = "孫悟空";

      names[2] = "豬八戒";

      names[3] = "沙和尚";

      4.1.3 數(shù)組元素的訪問

      數(shù)組創(chuàng)建之后,最常用的操作就是訪問數(shù)組元素,這包含為數(shù)組元素賦值和輸出數(shù)組元素中的值。訪問數(shù)組元素的方式是通過數(shù)組名結(jié)合數(shù)組下標(biāo)的方式完成的。

      接下來,通過實(shí)例來演示如何訪問數(shù)組元素,如例4-1所示。

      例4-1 Demo0401.java

      1 ?package com.aaa.p040103;

      2

      3 ?public class Demo0401 {

      4 ? public static void main(String[] args) {

      5 ? int[] nums = new int[3]; // 定義長度為3的整型數(shù)組

      6 ? nums[0] = 10; // 為數(shù)組元素賦值

      7 ? nums[1] = 20;

      8 ? nums[2] = 30;

      9 ? System.out.println(nums[0]); // 輸出數(shù)組元素中的值

      10 ? System.out.println(nums[1]);

      11 ? System.out.println(nums[2]);

      12 ? }

      13 ?}

      程序運(yùn)行結(jié)果如下:

      10

      20

      30

      在例4-1中,先創(chuàng)建了一個長度為3的整型數(shù)組,然后使用數(shù)組名結(jié)合下標(biāo)的方式分別為3個數(shù)組元素賦值。注意,數(shù)組的下標(biāo)必須寫在中括號內(nèi)。最后,使用打印輸出語句輸出每個數(shù)組元素內(nèi)的數(shù)據(jù)。

      4.1.4 length的使用

      要獲取數(shù)組的長度,可以通過數(shù)組對象的length屬性得到。每個數(shù)組都會有l(wèi)ength屬性,當(dāng)通過length屬性獲取了數(shù)組長度之后,就可以通過循環(huán)的方式,使用下標(biāo)逐一遍歷數(shù)組中的每個元素。

      接下來,我們使用length獲取數(shù)組長度,并通過循環(huán)遍歷數(shù)組元素,如例4-2所示。

      例4-2 Demo0402.java

      1 ?package com.aaa.p040104;

      2

      3 ?public class Demo0402 {

      4 ? public static void main(String[] args) {

      5 ? int[] nums = new int[3]; // 創(chuàng)建長度為3的數(shù)組對象

      6 ? nums[0] = 10; // 為數(shù)組元素賦值

      7 ? nums[1] = 20;

      8 ? nums[2] = 30;

      9 ? for(int i = 0;i < nums.length;i++) { // 使用length獲取數(shù)組長度,作為循環(huán)條件

      10 ? System.out.println(nums[i]); // 循環(huán)輸出每個元素

      11 ? }

      12 ? }

      13 ?}

      程序運(yùn)行結(jié)果如下:

      10

      20

      30

      在例4-2中,先定義了長度為3的整型數(shù)組,然后使用數(shù)組名結(jié)合下標(biāo)的方式為每個數(shù)組元素賦值,接著使用數(shù)組的length屬性獲取數(shù)組的長度,作為for循環(huán)的循環(huán)條件,最后通過for循環(huán)逐一遍歷數(shù)組元素,并打印輸出。

      4.1.5 使用foreach遍歷數(shù)組

      除了使用for循環(huán)遍歷數(shù)組外,Java中還有另外一種很簡潔的遍歷方法:foreach循環(huán)遍歷。這種方式也稱為增強(qiáng)for循環(huán),它的功能比較強(qiáng)大,遍歷時不需要依賴數(shù)組的長度和下標(biāo),即可實(shí)現(xiàn)數(shù)組遍歷。foreach循環(huán)的語法格式如下:

      for (數(shù)組中元素類型 臨時變量 : 數(shù)組對象變量){

      程序語句;

      }

      通過上面的語法結(jié)構(gòu)可以看出,foreach遍歷數(shù)組的時候不需要獲取數(shù)組長度,也不需要用索引去訪問數(shù)組中的元素,這是與for循環(huán)不同的地方。foreach循環(huán)會自動將數(shù)組中的元素逐一取出,存入一個臨時變量中,然后使用臨時變量進(jìn)行數(shù)據(jù)處理,從而完成數(shù)組元素的遍歷。

      接下來,通過案例來演示foreach循環(huán)遍歷數(shù)組,如例4-3所示。

      例4-3 Demo0403.java

      1 ?package com.aaa.p040105;

      2

      3 ?public class Demo0403 {

      4 ? public static void main(String[] args) {

      5 ? String[] names = {"唐僧","孫悟空","豬八戒","沙和尚"}; // 聲明數(shù)組并進(jìn)行初始化

      6 ? for(String name : names) { // 使用foreach循環(huán)逐一取出數(shù)組元素并存入臨時變量

      7 ? System.out.println(name); // 輸出臨時變量存儲的數(shù)據(jù)

      8 ? }

      9 ? }

      10 ?}

      程序運(yùn)行結(jié)果如下:

      唐僧

      孫悟空

      豬八戒

      沙和尚

      例4-3中,首先定義了一個數(shù)組對象,并初始化了4個字符串?dāng)?shù)據(jù)。然后使用foreach循環(huán)遍歷數(shù)組,每次循環(huán)時foreach都通過臨時變量存儲當(dāng)前遍歷到的元素,并將元素打印顯示。

      注意:foreach循環(huán)代碼簡潔,編寫方便,但是有其局限性,當(dāng)使用foreach遍歷數(shù)組時,只能訪問其中的元素,不能對元素進(jìn)行修改。

      接下來,通過案例進(jìn)一步演示在使用foreach循環(huán)的過程中,對元素進(jìn)行修改會有什么結(jié)果,如例4-4所示。

      例4-4 Demo0404.java

      1 ?package com.aaa.p040105;

      1

      1 ?public class Demo0404 {

      1 ? public static void main(String[] args) {

      1 ? String[] strs = new String[3]; // 創(chuàng)建一個長度為3的數(shù)組

      1 ? int i = 0;

      1 ? for(String str : strs) { // 循環(huán)遍歷數(shù)組

      1 ? str = new String("字符串:" + i ); // 修改每個遍歷到的值

      1 ? i++;

      1 ? }

      1 ? for(String str : strs) {

      1 ? System.out.println(str); // 打印數(shù)組中的值

      1 ? }

      1 ? }

      1 ?}

      程序運(yùn)行結(jié)果如下:

      null

      null

      null

      例4-4中,先定義一個長度為3的字符串?dāng)?shù)組。然后通過第1個foreach循環(huán),將遍歷到的每個數(shù)組元素的數(shù)據(jù)都進(jìn)行了修改。但在第2個foreach循環(huán)中,遍歷輸出的每個元素依舊是null。這說明在使用foreach循環(huán)遍歷時,遍歷的元素并沒有真正被修改。原因是第8行中只是將臨時變量str指向了一個新字符串,變量str和數(shù)組中的元素實(shí)際上沒有任何聯(lián)系。所以,foreach循環(huán)的過程中無法修改所遍歷的數(shù)據(jù)。因此,foreach并不能替代for循環(huán),僅僅是讓遍歷的方法變得更簡潔。

      4.1.6 基本類型數(shù)組的初始化

      按照數(shù)據(jù)類型的不同,數(shù)組可分為基本類型數(shù)組和引用類型數(shù)組。基本類型數(shù)組的特點(diǎn)是,數(shù)組元素的值是直接存儲在數(shù)組元素中的。所以,定義基本類型數(shù)組并初始化時,會先為數(shù)組分配空間,然后將數(shù)據(jù)直接存入對應(yīng)的數(shù)組元素中。基本類型數(shù)組的初始化示例如圖4.2所示。

      (a)定義值類型數(shù)組并由系統(tǒng)自動初始化 (b)為值類型數(shù)組設(shè)置數(shù)據(jù)

      圖4.2 值類型數(shù)組的初始化和設(shè)值

      在圖4.2中,左圖定義了一個值類型數(shù)組,也就是整型數(shù)組nums。該數(shù)組長度為5,初始化后每個數(shù)組元素的值都是0。右圖是為nums數(shù)組中的元素都設(shè)置一個整數(shù)值。從圖4.2中可以看出,值類型數(shù)組的數(shù)據(jù)都是直接存儲在數(shù)組元素中的。

      接下來,通過案例來演示值類型數(shù)組的初始化和設(shè)值,如例4-5所示。

      例4-5 Demo0405.java

      1 ?package com.aaa.p040106;

      2

      3 ?public class Demo0405 {

      4 ? public static void main(String[] args) {

      5 ? int[] nums = new int[5]; // 定義長度為5的數(shù)組,并動態(tài)初始化

      6 ? for(int n : nums) { // 使用foreach輸出每個元素值

      7 ? System.out.println(n);

      8 ? }

      9

      10 ? System.out.println("=========="); // 輸出分隔符

      11

      12 ? nums[0] = 34; // 為每個數(shù)組元素設(shè)置特定值

      13 ? nums[1] = 21;

      14 ? nums[2] = 15;

      15 ? nums[3] = 56;

      16 ? nums[4] = 71;

      17

      18 ? for(int i = 0;i < nums.length;i++) { // 使用for循環(huán)輸出每個元素

      19 ? System.out.println(nums[i]);

      20 ? }

      21 ? }

      22 ?}

      程序運(yùn)行結(jié)果如下:

      0

      0

      0

      0

      0

      ==========

      34

      21

      15

      56

      71

      在例4-5中,先定義了一個長度為5的整型數(shù)組。接著,使用foreach循環(huán)輸出數(shù)組元素中的數(shù)據(jù),此時數(shù)組中的數(shù)據(jù)都為0。然后,通過數(shù)組名結(jié)合下標(biāo)的方式,為每個數(shù)組元素設(shè)置特定數(shù)據(jù),最后使用for循環(huán)將數(shù)組元素的數(shù)據(jù)逐一打印出來。

      4.1.7 引用類型數(shù)組的初始化

      引用類型數(shù)組中存儲的是數(shù)據(jù)的引用地址。通過引用地址指向了實(shí)際存儲數(shù)據(jù)的內(nèi)存區(qū)域。下面通過定義一個Student類型的數(shù)組來演示引用類型數(shù)組的使用,如例4-6所示。

      例4-6 Demo0406.java

      1 ?package com.aaa.p040107;

      2

      3 ?class Student{ // 學(xué)生類

      4 ? String name; // 姓名

      5 ? int age; // 年齡

      6 ?}

      7

      8 ?public class Demo0406 {

      9 ? public static void main(String[] args) {

      10 ? Student[] stus = new Student[2]; // 創(chuàng)建長度為2的學(xué)生數(shù)組

      11 ? stus[0] = new Student(); // 為第一個數(shù)組元素存儲學(xué)生對象

      12 ? stus[0].name = "張三"; // 設(shè)置學(xué)生對象的屬性

      13 ? stus[0].age = 20;

      14

      15 ? stus[1] = new Student(); // 為第二個數(shù)組元素存儲學(xué)生對象

      16 ? stus[1].name = "李四"; // 設(shè)置學(xué)生對象的屬性

      17 ? stus[1].age = 18;

      18

      19 ? for(Student s : stus) { // 使用foreach循環(huán)輸出學(xué)生對象數(shù)據(jù)

      20 ? System.out.println(s.name + " " + s.age);

      21 ? }

      22 ? }

      23 ?}

      程序運(yùn)行結(jié)果如下:

      張三 20

      李四 18

      在例4-6中,先定義了一個長度為2的Student類型的數(shù)組。接著,為每個數(shù)組元素存儲一個學(xué)生類型的對象,并為存儲的學(xué)生對象設(shè)置屬性。然后,使用foreach循環(huán)輸出數(shù)組元素中的學(xué)生對象,將學(xué)生的姓名和年齡打印出來。

      為了便于大家更好地理解引用類型數(shù)組存儲數(shù)據(jù)的特點(diǎn)。下面通過一個圖例對引用類型數(shù)組的使用進(jìn)行說明,如圖4.3所示。

      (a)引用類型數(shù)組的初始化 (b)引用類型數(shù)組存儲數(shù)據(jù)

      圖4.3 引用類型數(shù)組的數(shù)據(jù)存儲方式

      圖4.3中,左圖是引用類型數(shù)組定義并初始化的情況,引用類型數(shù)組的元素默認(rèn)值都為null,不指向任何數(shù)據(jù)。右圖中,定義了學(xué)生類型的數(shù)組,數(shù)組長度為2,數(shù)組包含兩個元素。每個數(shù)組元素都存儲了一個地址,分別指向不同的學(xué)生對象。

      4.2 二維數(shù)組

      一維數(shù)組主要用于存儲線性數(shù)據(jù),比如存儲某校某年級所有學(xué)生一門課程的成績,這種數(shù)據(jù)存儲的結(jié)構(gòu)是單個維度的。但是在實(shí)際應(yīng)用中,一維數(shù)組并不能滿足所有需求,比如存儲某校某年級所有學(xué)生兩門課程的成績。所以,Java中提供了多維數(shù)組,但是Java中并沒有真正的多維數(shù)組結(jié)構(gòu),它的多維數(shù)組的本質(zhì)是讓數(shù)組元素再存儲一個數(shù)組,從而構(gòu)成多維數(shù)組的結(jié)構(gòu)。本節(jié)將以二維數(shù)組為例講解多維數(shù)組的用法。二維數(shù)組的數(shù)據(jù)結(jié)構(gòu)類似于一張表,包含行和列,下面展開詳細(xì)講解。

      4.2.1 二維數(shù)組的創(chuàng)建

      二維數(shù)組的結(jié)構(gòu)可以看作是一張表,其中包含行和列,分別對應(yīng)第一維度和第二維度。如圖4.4所示,是一個3行2列的二維數(shù)組的存儲結(jié)構(gòu)示意圖。

      圖4.4 3行2列二維數(shù)組結(jié)構(gòu)

      在Java中,聲明二維數(shù)組時,需要使用兩個中括號進(jìn)行定義,在分配二維數(shù)組元素空間時,需要指明兩個維度的數(shù)組長度。二維數(shù)組的創(chuàng)建和一維數(shù)組類似,也需要進(jìn)行數(shù)組聲明和數(shù)組空間分配,創(chuàng)建二維數(shù)組的語法如下:

      數(shù)據(jù)類型[][] 數(shù)組名; // 聲明二維數(shù)組變量

      數(shù)組名 = new 數(shù)據(jù)類型[第一維長度][第二維長度]; // 為二維數(shù)組分配空間

      當(dāng)然也可以將數(shù)組聲明和數(shù)組的內(nèi)存分配用一行代碼定義:

      數(shù)據(jù)類型[][] 數(shù)組名 = new 數(shù)據(jù)類型[第一維長度][第二維長度]; // 聲明二維數(shù)組并分配空間

      根據(jù)二維數(shù)組的語法,創(chuàng)建一個3行2列的整型二維數(shù)組的示例代碼如下:

      int[][] scores; // 聲明二維數(shù)組變量scores

      scores = new int[3][2]; // 為二維數(shù)組分配3行2列的內(nèi)存空間

      在上述示例代碼中,第1行聲明了一個整型二維數(shù)組變量scores,這個變量未指向任何數(shù)組空間。接著,第2行代碼先通過new運(yùn)算符創(chuàng)建了一個3行2列的整型二維數(shù)組空間。然后,將二維數(shù)組賦值給scores變量,因此 scores變量存儲了整型二維數(shù)組的地址。通過scores變量可以訪問二維數(shù)組對象空間的每個元素。對于二維數(shù)組的聲明和內(nèi)存分配,如圖4.5所示。

      (a)聲明整型二維數(shù)組變量但未指向數(shù)組對象空間 (b)聲明整型二維數(shù)組變量并指向二維數(shù)組對象空間

      圖4.5 二維數(shù)組聲明和內(nèi)存分配

      圖4.4中,左圖聲明了一個整型二維數(shù)組變量scores,因?yàn)闆]有指向任何數(shù)組對象,所以scores變量存儲的內(nèi)容是null。右圖在堆內(nèi)存中創(chuàng)建了一個3行2列的整型二維數(shù)組。右圖的scores變量存儲了這個二維數(shù)組的首地址。二維數(shù)組的第一維是一個長度為3的一維數(shù)組,這個一維數(shù)組的每個空間都指向到另外一個長度為2的一維數(shù)組,由此構(gòu)成了二維數(shù)組結(jié)構(gòu)。通過scores變量使用兩個維度的下標(biāo)可以訪問到二維數(shù)組中的每個數(shù)組元素。

      4.2.2 二維數(shù)組的內(nèi)存分配

      二維數(shù)組創(chuàng)建之后,就可以存儲數(shù)據(jù)到二維數(shù)組的元素空間中。二維數(shù)組元素的賦值方式與一維數(shù)組類似,也是3種方式:靜態(tài)初始化、動態(tài)初始化、通過數(shù)組下標(biāo)為數(shù)組賦值。

      1.靜態(tài)初始化

      二維數(shù)組的靜態(tài)初始化就是在聲明數(shù)組時,由開發(fā)者顯示指定二維數(shù)組元素的初始值。因?yàn)槎S數(shù)組有兩個維度,所以在設(shè)置數(shù)據(jù)的時候,要使用兩層大括號來體現(xiàn)兩個維度的結(jié)構(gòu)。如下是兩種二維數(shù)組靜態(tài)初始化的語法:

      // 聲明數(shù)組同時初始化,外面的大括號表示第一維元素,里面的大括號表示第二維元素

      數(shù)據(jù)類型[][] 數(shù)組名 = {{數(shù)據(jù)1,數(shù)據(jù)2,…},{數(shù)據(jù)1,數(shù)據(jù)2,…},…};

      // 先聲明二維數(shù)組,然后進(jìn)行初始化

      數(shù)據(jù)類型[][] 數(shù)組名 ;

      數(shù)組名 = new 數(shù)據(jù)類型[][]{{數(shù)據(jù)1,數(shù)據(jù)2,…},{數(shù)據(jù)1,數(shù)據(jù)2,…},…};

      上述語法中,二維數(shù)組靜態(tài)初始化時,初始化的數(shù)據(jù)要寫在兩層大括號中,這是與一維數(shù)組不同的地方。第1層大括號中定義的是第一維的數(shù)組元素,這些數(shù)組元素本身又是一個數(shù)組,元素之間以逗號分隔。第2層大括號中存儲的是實(shí)際的數(shù)據(jù)內(nèi)容,多個數(shù)據(jù)之間也以逗號分隔。另外,在第2種靜態(tài)初始的語法中,右邊表達(dá)式中的“[ ][ ]”內(nèi),也不允許寫數(shù)組長度,否則會發(fā)生語法錯誤。

      二維數(shù)組靜態(tài)初始化示例代碼如下:

      int[][] scores = {{78,65},{98,79},{87,89}}; // 聲明數(shù)組并進(jìn)行數(shù)組靜態(tài)初始化

      int[][] scores; // 先聲明數(shù)組變量

      scores = new int[][]{{78,65},{98,79},{87,89}}; // 再進(jìn)行靜態(tài)初始化

      2.動態(tài)初始化

      二維數(shù)組進(jìn)行動態(tài)初始化時,開發(fā)者需要指定兩個維度的數(shù)組長度,然后由系統(tǒng)自動為數(shù)組元素分配初始值。二維數(shù)組動態(tài)初始化的語法格式如下:

      數(shù)據(jù)類型[][] 數(shù)組名 = new 數(shù)據(jù)類型[第一維數(shù)組長度][第二維數(shù)組長度];

      二維數(shù)組在進(jìn)行動態(tài)初始化后,程序會根據(jù)指定的兩個維度的數(shù)組長度,創(chuàng)建對應(yīng)的數(shù)組元素空間,并為每個數(shù)組元素空間設(shè)置初始值。

      二維數(shù)組動態(tài)初始化的代碼示例如下:

      int[][] scores = new int[3][2]; // 創(chuàng)建3行2列的整形二維數(shù)組,元素的初始值都是0

      String[][] names = new String[3][2];// 創(chuàng)建3行2列的字符串二維數(shù)組,元素的初始值都為null

      3.通過數(shù)組下標(biāo)為數(shù)組賦值

      在二維數(shù)組創(chuàng)建之后,可以使用數(shù)組名結(jié)合二維數(shù)組行列下標(biāo)的方式,為二維數(shù)組空間中的每個元素賦值。使用二維數(shù)組下標(biāo)賦值的語法格式如下:

      數(shù)據(jù)類型[][] 數(shù)組名 = new 數(shù)據(jù)類型[第一維數(shù)組長度][第二維數(shù)組長度];

      數(shù)組名[第一維度下標(biāo)][第二維度下標(biāo)] = 數(shù)值;

      在通過數(shù)組下標(biāo)為數(shù)組元素賦值的時候,每個維度的數(shù)組下標(biāo)的取值范圍從0到對應(yīng)維度的數(shù)組長度減1為止。下標(biāo)超出這個范圍,會發(fā)生“ArrayIndexOutOfBoundsException”數(shù)組下標(biāo)越界的異常。

      通過數(shù)組下標(biāo)為元素賦值的示例代碼如下:

      String[][] names = new String[3][2]; // 聲明3行2列字符串二維數(shù)組

      names[0][0] = "張三"; // 通過2個維度的下標(biāo)為每個數(shù)組元素賦值

      names[0][1] = "李四";

      names[1][0] = "王五";

      names[1][1] = "趙六";

      names[2][0] = "孫七";

      names[2][1] = "錢八";

      4.2.3 嵌套循環(huán)存取二維數(shù)組

      二維數(shù)組有兩個維度,在訪問數(shù)組元素的時候要通過兩個下標(biāo)來訪問。因?yàn)閿?shù)組的下標(biāo)具有連續(xù)性的特點(diǎn),所以可以通過循環(huán)嵌套的方式來訪問二維數(shù)組的每個元素。

      接下來,通過循環(huán)嵌套的方式為一個3行2列的二維數(shù)組賦值,并用循環(huán)嵌套的方式輸出存入的數(shù)據(jù),如例4-7所示。

      例4-7 Demo0407.java

      1 ?package com.aaa.p040203;

      2 ?import java.util.Scanner;

      3

      4 ?public class Demo0407 {

      5 ? public static void main(String[] args) {

      6 ? Scanner sc = new Scanner(System.in); // 定義輸入掃描器對象,用于接受鍵盤輸入

      7 ? // 定義3行2列的二維數(shù)組,存儲3名學(xué)生的2門成績

      8 ? int[][] scores = new int[3][2];

      9 ? // 使用嵌套循環(huán)的方式為數(shù)組賦值, scores.length獲取第一維數(shù)組的長度

      10 ? for(int i = 0; i < scores.length; i++) {

      11 ? // scores[i].length獲取第二維數(shù)組的長度

      12 ? for(int j = 0; j < scores[i].length; j++) {

      13 ? System.out.println("請輸入第" + ( i + 1 ) + "個學(xué)生的第" + ( j + 1 ) +

      14 ? "門課成績:");

      15 ? scores[i][j] = sc.nextInt(); // 將輸入的數(shù)據(jù)存入對應(yīng)的數(shù)組位置

      16 ? }

      17 ? }

      18

      19 ? System.out.println("===================="); // 輸出分隔符

      20

      21 ? // 使用嵌套循環(huán)的方式打印二維數(shù)組元素, scores.length獲取第一維數(shù)組的長度

      22 ? for(int i = 0; i < scores.length; i++) {

      23 ? // scores[i].length獲取第二維數(shù)組的長度

      24 ? for(int j = 0; j < scores[i].length; j++) {

      25 ? int score = scores[i][j]; // 獲取當(dāng)前遍歷到的二維數(shù)組元素

      26 ? // 輸出分?jǐn)?shù)

      27 ? System.out.println("第" + (i + 1) + "個學(xué)生的第" + (j + 1) +

      28 ? "門課成績是:" + score);

      29 ? }

      30 ? }

      31

      32 ? }

      33 ?}

      程序運(yùn)行結(jié)果如下:

      請輸入第1個學(xué)生的第1門課成績:

      23

      請輸入第1個學(xué)生的第2門課成績:

      34

      請輸入第2個學(xué)生的第1門課成績:

      45

      請輸入第2個學(xué)生的第2門課成績:

      56

      請輸入第3個學(xué)生的第1門課成績:

      67

      請輸入第3個學(xué)生的第2門課成績:

      87

      ====================

      第1個學(xué)生的第1門課成績是:23

      第1個學(xué)生的第2門課成績是:34

      第2個學(xué)生的第1門課成績是:45

      第2個學(xué)生的第2門課成績是:56

      第3個學(xué)生的第1門課成績是:67

      第3個學(xué)生的第2門課成績是:87

      在例4-7中,先定義了一個輸入掃描器對象(Scanner),用于接受從鍵盤輸入的數(shù)據(jù)。接著,定義了一個3行2列的整型二維數(shù)組,用于存儲3個學(xué)生兩門課程的成績。然后使用嵌套循環(huán)實(shí)現(xiàn)二維數(shù)組元素的賦值。scores.length是第1層循環(huán)的終止條件,它表示的是第一維度數(shù)組的長度。scores[i].length是第二層循環(huán)的終止條件,它表示的是第二維度數(shù)組的長度。在第2層循環(huán)內(nèi)部,使用scores[i][j]表示訪問到的某個二維數(shù)組元素,用于存儲用戶通過鍵盤輸入的數(shù)據(jù)。嵌套循環(huán)結(jié)束后,這個二維數(shù)組的所有元素都會被賦值。接下來通過另外一個嵌套循環(huán),將二維數(shù)組內(nèi)的所有元素逐一打印輸出。

      知識點(diǎn)撥:Java中的多維數(shù)組本質(zhì)上是在數(shù)組中存儲數(shù)組,是在一維數(shù)組的基礎(chǔ)上衍生出來的,因此理論上可以定義任何維度的數(shù)組。定義二維數(shù)組的時候需要使用兩個中括號"[ ][ ]",以此類推,定義三維、四維數(shù)組只要定義對應(yīng)個數(shù)的中括號即可。

      4.2.4 非對稱型數(shù)組

      前面講的二維數(shù)組用的都是矩陣數(shù)組,也就是數(shù)組的第二維度的長度都是一樣的,是等行等列的對稱結(jié)構(gòu)。但是,Java中還有一種非對稱的數(shù)組結(jié)構(gòu),被稱為非對稱型數(shù)組。對稱型數(shù)組和非對稱型數(shù)組的結(jié)構(gòu)如圖4.6所示。

      (a)對稱型數(shù)組(矩形數(shù)組) (b)非對稱型數(shù)組(不規(guī)則數(shù)組)

      圖4.6 對稱型數(shù)組和非對稱型數(shù)組

      對稱型的3行4列數(shù)組有12個元素,但是非對稱型數(shù)組的元素個數(shù)是不確定的。這里,我們定義一個非對稱型數(shù)組,并進(jìn)行靜態(tài)初始化,然后輸出一維數(shù)組元素指向的數(shù)組中的最后一個元素,示例代碼如下:

      int[][] scores = {{1,2,3},{5,6,7,8},{9,10}}; // 用靜態(tài)初始化的方式定義非對稱型數(shù)組

      System.out.println(scores[0][2]); // 輸出第一維下標(biāo)為0的數(shù)組的最后一個元素

      System.out.println(scores[1][3]); // 輸出第一維下標(biāo)為1的數(shù)組的最后一個元素

      System.out.println(scores[2][1]); // 輸出第一維下標(biāo)為2的數(shù)組的最后一個元素

      在上述示例代碼中,聲明的二維數(shù)組,第一維長度是3。但是,第二維長度各不相同,長度分別是:3,4,2。因此,第一維數(shù)組元素關(guān)聯(lián)的數(shù)組的最后一個元素的下標(biāo)是各不相同的。

      4.3 數(shù)組的排序與查找

      使用數(shù)組處理數(shù)據(jù)的時候,除了要對數(shù)據(jù)進(jìn)行存儲,大部分時候需要對數(shù)據(jù)進(jìn)行查找和篩選,而查找數(shù)據(jù)的時候又往往需要對數(shù)據(jù)進(jìn)行排序處理。比如,要找一個分?jǐn)?shù)最高的成績,或者年齡最小的學(xué)生,這時就需要在查找的過程中進(jìn)行數(shù)據(jù)排序。

      4.3.1 數(shù)組元素排序

      對數(shù)組中的數(shù)據(jù)進(jìn)行排序的算法有很多種,對于初學(xué)者而言,“冒泡排序”是最簡單易懂的方法。冒泡排序的核心特點(diǎn),就是先比較相鄰兩個元素的大小,然后根據(jù)排序規(guī)則進(jìn)行換位。

      如圖4.7所示,是對一維數(shù)組中的5個數(shù)字:56,32,8,76,12進(jìn)行冒泡排序,要求排序之后,數(shù)組中的數(shù)據(jù)按照從小到大的次序排列。

      圖4.7 冒泡排序

      圖4.7中,在開始排序時,5個數(shù)字沒有按從小到大的次序進(jìn)行排列。接著開始進(jìn)行第1輪排序,排序的時候依次對相鄰的兩個數(shù)字比較大小,如果前面的數(shù)字大于后面的數(shù)字,則將這兩個數(shù)字交換位置,否則就不進(jìn)行換位。參與排序的5個數(shù)字全都比較一遍并做了相應(yīng)的換位之后,數(shù)值最大的76排在了最后的位置上,這個數(shù)字不再參與下一輪的比較。第1輪排序一共進(jìn)行了4次比較和換位。在第2輪排序時,排除了上一輪的最大值76后,只需要對4個數(shù)字進(jìn)行排序。排序的過程依舊是比較和換位。最終經(jīng)過3次比較,找到了本輪的最大值56。第3輪排序時,將前兩輪的最大值72和56排除掉,只需要對剩下的3個數(shù)字進(jìn)行排序。最終經(jīng)過2次比較和換位,找到了本輪的最大值32。第4輪排序時,將前3輪的最大值72、56、32排除掉,只需要對剩下的2個數(shù)字進(jìn)行排序,最終經(jīng)過1次比較找到了本輪的最大值12。經(jīng)過4輪排序,5個數(shù)字實(shí)現(xiàn)了從小到大的排列。

      經(jīng)過上面的排序過程可以發(fā)現(xiàn),排序的輪數(shù)等于參與排序的數(shù)字的個數(shù)減1。而每一輪排序的次數(shù)等于本輪參與排序的數(shù)字個數(shù)減1。這是因?yàn)槊恳惠喤判蚨紩业奖据喌淖畲笾担谙乱惠喤判驎r這個最大值不再參與比較,所以隨著排序輪數(shù)的增加,參與比較的數(shù)字在減少,這是冒泡排序的一個基本規(guī)律。

      在了解了冒泡排序的基本原理后,下面用代碼實(shí)現(xiàn)冒泡排序的過程,如例4-8所示:

      例4-8 Demo0408.java

      1 ?package com.aaa.p040301;

      2

      3 ?public class Demo0408 {

      4 ? public static void main(String[] args) {

      5 ? int[] nums = {56, 32, 8, 76, 12}; // 定義要排序的整形數(shù)組

      6 ? System.out.println("=========排序前===========");

      7 ? for(int n : nums) { // 循環(huán)輸出初始的數(shù)組數(shù)據(jù)

      8 ? System.out.print(n+" ");

      9 ? }

      10 ? System.out.println(); // 換行

      11 ? // 使用雙重循環(huán)實(shí)現(xiàn)冒泡排序,外層循環(huán)控制排序比較的輪數(shù)

      12 ? for(int i = 1;i < nums.length; i++) {

      13 ? for(int j = 0;j < nums.length - i;j++) { // 內(nèi)層循環(huán)控制每一輪比較的次數(shù)

      14 ? if(nums[j] > nums[j + 1]) { // 每次比較相鄰的兩個元素的大小

      JAVA編程講義之?dāng)?shù)組

      15 ? // 若前元素大于后元素,則交換位置,先將前元素的數(shù)據(jù)存入臨時變量

      16 ? int temp = nums[j];

      17 ? nums[j] = nums[j + 1]; // 將后元素的數(shù)據(jù)存到前元素中

      18 ? nums[j + 1] = temp; // 將臨時變量數(shù)據(jù)存儲到后元素中

      19 ? }

      20 ? }

      21 ? }

      22 ? System.out.println("=========排序后===========");

      23 ? for(int n : nums) { // 循環(huán)輸出排序后的數(shù)組數(shù)據(jù)

      24 ? System.out.print(n + " ");

      25 ? }

      26 ? }

      27 ?}

      程序運(yùn)行結(jié)果如下:

      =========排序前===========

      56 32 8 76 12

      =========排序后===========

      8 12 32 56 76

      在例4-8中,先定義了一個整型一維數(shù)組,存儲了要排序的5個數(shù)字。接著使用循環(huán)將排序前的這5個數(shù)字打印輸出,用于和排序后的結(jié)果做對比。然后,使用嵌套的for循環(huán)實(shí)現(xiàn)冒泡排序的算法過程。在嵌套for循環(huán)中,外層循環(huán)用于控制排序比較的輪數(shù)。內(nèi)層循環(huán)用于控制每輪排序比較的次數(shù)。在內(nèi)層循環(huán)中,每次做比較時,如果參與比較的兩個元素,前面的元素比后面的元素大,則要進(jìn)行換位。換位的時候,先定義一個臨時變量,用于存儲參與比較的前面的數(shù)組元素,接著把后面的元素存入前面的元素中,最后再把臨時變量存儲的數(shù)據(jù)存入后面數(shù)組元素中,從而完成元素?fù)Q位。嵌套循環(huán)執(zhí)行完成之后,數(shù)組元素就完成了排序過程。最后,使用循環(huán)輸出排序后的數(shù)組數(shù)據(jù)。

      編程技巧:對于初學(xué)者而言,冒泡排序的算法代碼不太容易掌握。大家只要記住下面四句話,那么冒泡排序就很容易寫出來:N元數(shù)組冒泡序,兩兩相比小前移。外層循環(huán)從1始,內(nèi)層循環(huán)減i去。

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

      通過排序可以將數(shù)組元素排出大小順序,排序的目的是為了更有效地查找數(shù)據(jù)。而對于數(shù)據(jù)的查找,也有很多算法,本節(jié)主要講解順序查找和二分查找。

      1.順序查找

      順序查找法是最簡單的查找方法。可以對數(shù)組中的元素按照下標(biāo)依次對比,直到查找到目標(biāo)元素或者將所有數(shù)組元素遍歷完畢為止。順序查找法的效率較低,比如在N個元素中查找目標(biāo)數(shù)據(jù),平均要查找N/2次。所以,順序查找法一般用于對少量數(shù)據(jù)進(jìn)行查找,或者對未排序數(shù)據(jù)進(jìn)行查找。

      接下來,演示從有10個元素的整型數(shù)組中,使用順序查找法查找數(shù)字13,找到則輸出元素在數(shù)組中的下標(biāo),找不到則進(jìn)行提示,如例4-9所示。

      例4-9 Demo0409.java

      1 ?package com.aaa.p040302;

      2

      3 ?public class Demo0409 {

      4 ? public static void main(String[] args) {

      5 ? // 定義長度為10的整形數(shù)組,并初始化

      6 ? int[] nums = {34, 32, 45, 67, 98, 43, 31, 47, 13, 22};

      7 ? int searchNum = 13; // 定義要查找的目標(biāo)數(shù)據(jù)

      8 ? int index = -1; // 定義變量記錄查找到的目標(biāo)數(shù)據(jù)位置

      9 ? for(int i = 0; i < nums.length; i++) { // 循環(huán)遍歷數(shù)組,用順序查找法查找目標(biāo)數(shù)據(jù)

      10 ? if(nums[i] == searchNum) { // 判斷遍歷的當(dāng)前元素和目標(biāo)數(shù)據(jù)是否相等

      11 ? index = i; // 如果相等則記錄目標(biāo)數(shù)據(jù)在數(shù)組中的位置

      12 ? break; // 結(jié)束循環(huán)

      13 ? }

      14 ? }

      15 ? if(index == -1) { // 循環(huán)結(jié)束后,判斷記錄目標(biāo)數(shù)據(jù)位置是否為-1

      16 ? // 如果記錄的位置為-1,說明沒有找到數(shù)據(jù)

      17 ? System.out.println("在數(shù)組中沒有要找到的目標(biāo)數(shù)據(jù)");

      18 ? }else {

      19 ? // 如果記錄的位置不為-1,則說明找到了目標(biāo)數(shù)據(jù)

      20 ? System.out.println("找到了目標(biāo)數(shù)據(jù),位置是:" + index);

      21 ? }

      22

      23 ? }

      24 ?}

      程序運(yùn)行結(jié)果如下:

      找到了目標(biāo)數(shù)據(jù),位置是:8

      在例4-9中,先定義了一個整型一維數(shù)組,存儲了10個數(shù)字。接著,定義了一個變量存儲要查找的目標(biāo)數(shù)據(jù)13。然后,定義index變量用于記錄查找結(jié)果,index變量的初始值設(shè)為-1。接著使用循環(huán)逐一獲取數(shù)組中的元素與目標(biāo)數(shù)據(jù)進(jìn)行比較。如果數(shù)組元素與目標(biāo)數(shù)據(jù)相等,就說明在數(shù)組中找到了目標(biāo)數(shù)據(jù),則用index存儲當(dāng)前數(shù)組元素的下標(biāo)位置,然后退出循環(huán)。在循環(huán)結(jié)束后判斷index的值,如果index值不是-1,則說明在數(shù)組元素中找到了目標(biāo)數(shù)據(jù),index存儲了目標(biāo)數(shù)據(jù)在數(shù)組中的位置,則將該位置打印輸出。否則,說明數(shù)組中不存在查找的目標(biāo)值,則打印輸出沒有找到的提示。

      2.二分查找

      二分查找法是查找效率比較高的查找算法,該方法的核心是在數(shù)組數(shù)據(jù)有序的基礎(chǔ)上,在數(shù)組中標(biāo)記低位和高位以限定查找范圍,并用查找范圍內(nèi)的中間位置的數(shù)據(jù)和目標(biāo)數(shù)據(jù)進(jìn)行比較,不斷調(diào)整低位和高位的索引位置從而縮小查找范圍,最終找到目標(biāo)值。如果在N個數(shù)據(jù)的范圍內(nèi)進(jìn)行二分查找,則平均會執(zhí)行l(wèi)og2N+1次查找比較。

      如圖4.8所示,是在長度為10的整型數(shù)組中,使用二分查找法,查找數(shù)據(jù)47的過程。

      圖4.8 二分查找法

      圖4.8中,初始定義了長度為10的整型數(shù)組,并存儲了10個整數(shù)。然后,對數(shù)組進(jìn)行排序。接著,按照二分查找法的算法規(guī)則,在數(shù)組中標(biāo)記了低位(low)和高位(high)的索引位置,低位的索引位置初始為0,高位的索引位置初始為9(數(shù)組長度減1)。然后,通過低位和高位索引位置計(jì)算出一個中間位置,計(jì)算方法是:中間位置=(低位+高位)/2。根據(jù)這個公式計(jì)算得出中間位置的索引是4,此時使用該位置上的數(shù)據(jù)34和目標(biāo)數(shù)據(jù)47做對比,目標(biāo)數(shù)據(jù)47大于34,那么根據(jù)二分查找法的規(guī)則,為了縮小查找范圍,要將低位索引變?yōu)橹虚g索引加1,改變后低位索引的值就是5。接著使用改變后的低位索引和高位索引,重新計(jì)算得出一個新的中間位置(5+9)/2 = 7,此時中間位置7對應(yīng)的數(shù)據(jù)是47,這個就是查找的目標(biāo)數(shù)據(jù)。到此,二分查找法的整個過程結(jié)束。

      接下來,使用代碼演示的二分查找法的具體過程,如例4-10所示。

      例4-10 Demo0410.java

      1 ?package com.aaa.p040302;

      2

      3 ?public class Demo0410 {

      4 ? public static void main(String[] args) {

      5 ? // 定義長度為10的整形數(shù)組,并初始化

      6 ? int[] nums = {34, 32, 45, 67, 98, 43, 31, 47, 13, 22};

      7 ? System.out.println("=========排序前===========");

      8 ? for(int n : nums) { // 循環(huán)輸出排序前的數(shù)組數(shù)據(jù)

      9 ? System.out.print(n+" ");

      10 ? }

      11 ? System.out.println(); // 輸出換行

      12 ? // 使用雙重循環(huán)實(shí)現(xiàn)冒泡排序,外層循環(huán)控制排序比較的輪數(shù)

      13 ? for(int i = 1;i < nums.length;i++) { // 內(nèi)層循環(huán)控制每一輪比較的次數(shù)

      14 ? for(int j = 0; j < nums.length - i;j++) { // 每次比較相鄰的兩個元素的大小

      15 ? if(nums[j] > nums[j + 1]) {

      16 ? // 如果前元素大于后元素,則交換位置,先將前元素的數(shù)據(jù)存入臨時變量

      17 ? int temp = nums[j];

      18 ? nums[j] = nums[j + 1]; // 將后元素的數(shù)據(jù)存到前元素中

      19 ? nums[j + 1] = temp; // 將臨時變量數(shù)據(jù)存儲到后元素中

      20 ? }

      21 ? }

      22 ? }

      23

      24 ? System.out.println("=========排序后===========");

      25 ? for(int n : nums) { // 循環(huán)輸出排序后的數(shù)組數(shù)據(jù)

      26 ? System.out.print(n + " ");

      27 ? }

      28 ? System.out.println(); // 輸出換行

      29 ? System.out.println("=========使用二分查找法===========");

      30 ? // 使用二分法查找數(shù)據(jù)

      31 ? int searchNum = 47; // 定義要查找的目標(biāo)數(shù)據(jù)

      32 ? int index = -1; // 定義變量記錄查找到的目標(biāo)數(shù)據(jù)的位置

      33 ? int low = 0; // 定義低位索引變量,初始為0

      34 ? int high = nums.length - 1; // 定義高位索引變量,初始為數(shù)組長度減1

      35 ? int middle = -1; // 定義中間位置變量,初始為-1

      36 ? do { // 通過循環(huán)實(shí)現(xiàn)二分查找過程

      37 ? middle = (low + high) / 2; // 計(jì)算中間位置

      38 ? if(nums[middle] == searchNum) {// 使用中間位置對應(yīng)的數(shù)據(jù)和目標(biāo)數(shù)據(jù)比較

      39 ? index = middle; // 如果兩個數(shù)據(jù)相等,則用index存儲中間位置

      40 ? break; // 退出循環(huán)

      41 ? }

      42 ? // 如果中間數(shù)據(jù)大于目標(biāo)數(shù)據(jù),則將高位索引設(shè)置為中間位置減1

      43 ? if(nums[middle] > searchNum) {

      44 ? high = middle - 1;

      45 ? }else {

      46 ? low = middle + 1; // 否則,將低位索引設(shè)置為中間位置加1

      47 ? }

      48 ? }while(low <= high); // 循環(huán)條件是低位索引位置小于高位索引位置

      49 ? // 輸出二分查找結(jié)果

      50 ? if(index == -1) {

      51 ? // 如果index記錄的位置是-1,說明沒有找到目標(biāo)值

      52 ? System.out.println("在數(shù)組中沒有找到目標(biāo)值");

      53 ? }else{

      54 ? // 如果index記錄的位置不是-1,說明找到了目標(biāo)值

      55 ? System.out.println("找到了目標(biāo)值:" + searchNum + "它的索引位置是:" + index);

      56 ? }

      57 ? }

      58 ?}

      程序運(yùn)行結(jié)果如下:

      =========排序前===========

      34 32 45 67 98 43 31 47 13 22

      =========排序后===========

      13 22 31 32 34 43 45 47 67 98

      =========使用二分查找法===========

      找到了目標(biāo)值:47 它的索引位置是:7

      在例4-10中,先定義了長度為10的整形數(shù)組,并存儲了10個整數(shù)。接著,輸出了排序前的數(shù)組元素。然后,對數(shù)組進(jìn)行了排序,并輸出了排序后的數(shù)組元素。接著,定義了二分查找法需要的相關(guān)變量。其中,低位索引變量的初始值是0,高位索引變量的初始值是9(數(shù)組長度減1)。然后,使用do...while循環(huán)實(shí)現(xiàn)二分查找法的算法過程。在循環(huán)開始的時候,先通過低位索引和高位索引計(jì)算出中間位置。接著,使用中間位置上對應(yīng)的數(shù)據(jù)和目標(biāo)數(shù)據(jù)做對比,如果中間位置上的數(shù)據(jù)和目標(biāo)數(shù)據(jù)相等,那就記錄中間位置的索引值,查找到此結(jié)束。如果中間位置對應(yīng)的數(shù)據(jù)比目標(biāo)值大,那么根據(jù)二分查找法的規(guī)則,為了縮小查找范圍,要將高位索引設(shè)置為中間位置索引減1。如果中間位置對應(yīng)的數(shù)據(jù)比目標(biāo)值小,那么要將低位索引設(shè)置為中間位置索引加1。只要低位索引小于等于高位索引,這個循環(huán)過程就一直持續(xù),直到找到目標(biāo)數(shù)據(jù)為止。最后,在循環(huán)結(jié)束后,使用記錄目標(biāo)數(shù)據(jù)索引值的index變量進(jìn)行判斷,如果該變量的值是-1,則提示沒有找到目標(biāo)數(shù)據(jù),否則說明找到了目標(biāo)數(shù)據(jù),并將目標(biāo)值在數(shù)組中的索引打印出來。

      4.4 本章小結(jié)

      ? ?Java中使用數(shù)組需要3個步驟:聲明數(shù)組、創(chuàng)建數(shù)組對象空間、為數(shù)組元素賦值。

      ? ?為數(shù)組元素賦值可以使用靜態(tài)初始化、動態(tài)初始化、通過數(shù)組下標(biāo)為數(shù)組元素賦值。

      ? ?訪問數(shù)組中的元素時,要使用數(shù)組名加下標(biāo)的方式訪問。

      ? ?通過數(shù)組的length屬性可以獲取數(shù)組的長度。

      ? ?除了使用for循環(huán)結(jié)合下標(biāo)的方式遍歷數(shù)組,還可以使用foreach方式遍歷數(shù)組。

      ? ?基本類型的數(shù)組,其數(shù)組元素空間存儲的都是數(shù)據(jù)本身。

      ? ?引用類型的數(shù)組,其數(shù)組元素空間存儲的是數(shù)據(jù)的地址。

      ? ?二維數(shù)組就是讓數(shù)組元素再存儲一個數(shù)組,二維數(shù)組有兩個維度對應(yīng)行和列。

      ? ?二維數(shù)組的內(nèi)存分配和一維數(shù)組類似,也有3種方式:靜態(tài)初始化、動態(tài)初始化、使用數(shù)組下標(biāo)賦值。

      ? ?對二維數(shù)組而言,非對稱型數(shù)組是指數(shù)組的第二維的長度各不相等。

      ? ?冒泡排序的算法核心是相鄰兩個元素進(jìn)行比較和換位

      ? ?對數(shù)組元素查找的常用方法有:順序查找法和二分查找法

      4.5 理論測試與實(shí)踐練習(xí)

      1.填空題

      1.1 數(shù)組的元素通過 來訪問,訪問數(shù)組的長度用 。

      1.2 JVM將數(shù)組的存儲在 (堆或棧)中。

      1.3 數(shù)組下標(biāo)訪問超出索引范圍時拋出 異常。

      1.4 數(shù)組創(chuàng)建后其大小 (能/不能)改變。

      1.5 Java中數(shù)組的最小下標(biāo)是 。

      2.選擇題

      2.1 定義了一維int類型數(shù)組a[10]后,下面錯誤的引用是( )

      A.a(chǎn)[0]=1; B.a(chǎn)[10] = 2; C.a(chǎn)[0] = 5*2; D.a(chǎn)[1] = a[2]*a[0];

      2.2 下面二維數(shù)組初始化語句中 ,正確的是( )

      A.float b[2][2]={0.1,0.2,0.3,0.4};

      B.int a[][]={{1,2},{3,4}};

      C.int a[2][] = {{1,2},{3,4}};

      D.float a[2][2]={0};

      2.3 數(shù)組的第3個元素表示為( )

      A.a(chǎn)(3) B.a(chǎn)[3] C.a(chǎn)(2) D.a(chǎn)[2]

      2.4 通過哪些方式能夠?yàn)閿?shù)組賦值( )

      A.靜態(tài)初始化 B.動態(tài)初始化 C.使用數(shù)組下標(biāo)賦值 D.聲明數(shù)組變量

      2.5 關(guān)于字符串類型的數(shù)組,說話正確的是( )

      A.其數(shù)組的默認(rèn)值是’’ B.其數(shù)組的默認(rèn)值是null

      C.?dāng)?shù)組的長度可以任意變化 D.可以存儲整形數(shù)值

      3.思考題

      3.1 請簡述什么時候?yàn)閿?shù)組分配內(nèi)存?

      3.2 請簡述數(shù)組一旦被創(chuàng)建,大小能不能改變?

      3.3 請簡述順序查找法的過程?

      4.編程題

      4.1 定義整形數(shù)組,存放5個學(xué)生的成績【成績值自己設(shè)定】,將成績從大到小排序,獲得成績之和,平均成績,最小成績,最大成績。

      4.2定義長度為10的整形數(shù)組,并存儲10個數(shù)字。再通過鍵盤輸入一個數(shù)字,使用二分查找法在數(shù)組中查找輸入的數(shù)字是否存在。

      Java 數(shù)據(jù)結(jié)構(gòu)

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【Java 網(wǎng)絡(luò)編程】TCP 服務(wù)器端 客戶端 簡單示例
      下一篇:[Java][圖形程序設(shè)計(jì)Swing][學(xué)習(xí)筆記]
      相關(guān)文章
      国产精品国产亚洲区艳妇糸列短篇 | 亚洲国产成人久久笫一页| 亚洲午夜在线电影| 国产亚洲大尺度无码无码专线| 精品亚洲国产成人av| 亚洲精品美女久久7777777| 国产人成亚洲第一网站在线播放| 亚洲日本香蕉视频观看视频| 亚洲最大免费视频网| 亚洲美免无码中文字幕在线| 久久久亚洲欧洲日产国码二区| 亚洲人成在线影院| 少妇中文字幕乱码亚洲影视| 亚洲综合国产精品| 亚洲黄色三级网站| 亚洲成A∨人片在线观看无码| 亚洲国产韩国一区二区| 亚洲一区二区三区在线网站| 日韩亚洲产在线观看| 亚洲男人的天堂网站| 欧洲亚洲综合一区二区三区| 亚洲国产精品第一区二区三区| 亚洲国产成人久久精品软件| 自拍偷自拍亚洲精品偷一| 国产亚洲精品第一综合| 亚洲中文字幕无码专区| 亚洲无码在线播放| 久久亚洲国产伦理| 亚洲视频在线观看视频| 亚洲中文字幕人成乱码 | 亚洲中字慕日产2020| 亚洲入口无毒网址你懂的| 中文字幕无码亚洲欧洲日韩| 亚洲av色香蕉一区二区三区| 亚洲高清免费视频| 亚洲精品二区国产综合野狼 | 亚洲AV无码男人的天堂| 亚洲国产成人VA在线观看| 亚洲色婷婷一区二区三区| 亚洲电影一区二区| 亚洲人成网站18禁止久久影院 |