Java 程式設計()  第 四章 陣列資料結構  上一頁    下一頁

 

4-3 有序陣列結構

內容:

  • 4-3-1 有序陣列結構簡介

  • 4-3-2 範例研討:建立有序陣列

  • 4-3-3 範例研討:二分搜尋法

  • 4-3-4 範例研討:有序陣列插入元素

  • 4-3-5 自我挑戰:有序陣列元素處理

4-3-1 有序陣列結構簡介

4-6 為有序陣列結構的示意圖,資料在陣列中存放有依照某一個關鍵字(或稱主鍵)的大小排列。這種排列方式的搜尋速度會比無序排列快許多。如果資料沒有依照大小排序,搜尋某一筆資料必須採用『線性搜尋法』,也就是由資料最前頭,一筆接一筆的比對,找出所要資料的位置。如果資料有一萬筆,運氣好第一筆就找到,運氣不好,找了一萬筆都沒有找到(速度為 n)。如果採用有序陣列排序的話,可以採用『二分搜尋法』,平均搜尋的速度是 log2nn 表示資料筆數,如此速度就比有無序排序快許多。但因資料有依照主鍵大小排序,在作插入的時候,必須找到適當位置才可插入,而且必須經過適當的移位,才可以移動出一個空間,這遠比無序排列困難許多。

4-6 有序陣列的儲存順序

4-3-2 範例研討:建立有序陣列

(A)程式功能:Ex4_2.java

吾人需要一個空間為 50 的有序陣列結構,來驗證陣列的處理方式,期望執行後能顯示下列結果。

D:\Java2_book\chap4>javac Ex4_2.java

 

D:\Java2_book\chap4>java Ex4_2

 

== 目前序陣列有 40 筆資料 ==

 2   4   6   8  10  12  14  16  18  20

22  24  26  28  30  32  34  36  38  40

42  44  46  48  50  52  54  56  58  60

62   64  66  68  70  72  74  76  78  80

(B)程式範例

4-7 為其程式架構,包含 num[] point 兩個類別變數,與一個 main() 主程式。

4-7 Ex4_2 程式架構

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

//Ex4_2.java

/* 製作有序陣列的基本架構 */

 

import java.util.*;

public class Ex4_2{

  static int num[] = new int[50];     // 宣告陣列空間

  static int point;                   // 宣告游標變數

  public static void main(String args[]) {

      point = -1;      // 游標初值

      for (int i=0; i< 40; i++){        //給予陣列初值

          num[i] = (i+1) *2;           //存入有序資料

          point = point + 1;           //游標指示目前位置

      }

// 列印陣列內容     

      System.out.printf("\n== 目前序陣列有 %d 筆資料 ==\n", point+1);   

      for(int i=0; i<=point; i++) {

           System.out.printf("%2d  ", num[i]);

            if((i+1) % 10 == 0)

               System.out.printf("\n");    //列印10, 換行

      }

      System.out.printf("\n");           // 列印完畢, 換行

   }

}

4-3-3範例研討:二分搜尋法

(A)程式功能:Ex4_3.java

數學老師利用一個二維陣列 score[][] 儲存某一班級學生的成績,陣列第一個元素score[k][0]  存放學生學號,由 411101 ~ 411150;第二個元素 score[k][1] 存放數學成績,由 00 ~ 100 分,如:{411101, 70}, {411102, 80}, {411103, 75}, {411104, 90}, {411105, 85}, {4111106, 65}, {411107, 83}, {411108, 78}, {411109, 67}, (411110, 72)...等等。陣列是依照學號由低到高排列。

請編寫一程式,允許輸入學生學號,則輸出該學生的成績。程式中先寫一小程式填入陣列內每一位同學的學號與成績,成績採 00 ~ 100 之間的亂數,之後印出全班成績,接著再編寫一個二分搜尋程式。期望操作介面如下:

D:\Java2_book\chap4>javac Ex4_3.java

 

D:\Java2_book\chap4>java Ex4_3

=== 411101 ~ 411150 成績列印 ===

   7  50  73  24   8  11  93  68  68   0

  52   5  39  26  48  31  49   3  77  71

  29   3  62  96  17  26  65  65   1  43

  66  68  27  92   1   8  69  62  66  51

  44  31  46  61  14  95   3  12   2  50

請輸入欲尋找的學生學號 => 411120

學號 411120 成績是 71

(B)系統分析

『二分搜尋法』是由已排序(由大到小或由小到大排列)的陣列裡,搜尋某一筆資料,圖 4-8 為其運作程序。假設 a 陣列已由小到大排序完成(a[low] ~ a[high]),key 變數儲存欲尋找的資料,首先比對 a 陣列的中間元素(mid)的內容,如果 key = a [mid],則資料找到;如果 key < a[mid],則表示資料位於a[low] a[mid] 之間,則 mid 取代 high;如果 key > a[mid],則資料位於 a[mid] ~ a[high] 之間,mid 取代 low 內容。沒有找到資料的話,則將搜尋目標移到前半段或後半段繼續尋找,但還是由 a[low] ~ a[high] 搜尋(low high 可能會改變);如此依此類推,一直到找到資料或搜尋完畢為止。由此可見,此演算法每次將所有陣列資料缺切一半,再決定位於前段或後段,因此稱之為『二分搜尋法』。

此演算法較困難的地方是,如果找不到資料,如何去判斷與結束。其實,我們可以掌握一個重點,當 high 還是大於 low 的時候,表示還有資料未搜尋到;如果 high 小於或等於 low 時,表示已搜尋完所有資料,還未找到資料,則表示沒有該筆資料。

4-8 二分搜尋法

(C)程式範例

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

//Ex4_3.java

// 二分搜尋法

 

import java.util.Scanner;

import java.lang.Math;

public class Ex4_3 {

     public static void main(String args[]) {

          Scanner keyin = new Scanner(System.in);

          int a[][], value, flag, low, high, mid;

          a = new int[50][2];

          int number = 411101;

          for(int i=0; i<a.length; i=i+1){

              a[i][0] = number + i;

              a[i][1] = (int)(Math.random()*100);

          }

 

          /* 列印全班成績 */

          System.out.printf("=== 411101 ~ 411150 成績列印 ===\n");

          for(int i=0; i<a.length; i++) {

               System.out.printf("%4d", a[i][1]);

               if((i+1) % 10 == 0)

                   System.out.printf("\n");

          }       

 

          System.out.printf("請輸入欲尋找的學生學號 => ");

          value = keyin.nextInt();

 

          /*   二分搜尋法 */

          low = 0; high = 49;mid=0;

          flag=0;                     // 設定是否找到旗號

          while((low+1) < high) {        // 陣列是否搜尋完

              mid = (low + high)/2;

              if (value == a[mid][0]) {    // 比對陣列中間元素

                   flag = 1;           // 找到了, 設定旗號並離開

                   break;

              }

              else if (value > a[mid][0])    // 在陣列的後半段

                    low = mid;

              else                     // 在陣列的前半段

                    high = mid;

          }

         

          if (flag == 1)

            System.out.printf("學號 %d 成績是 %d\n", a[mid][0], a[mid][1]);

          else

            System.out.printf("沒有 %d 學號學生\n", value);

    }

}

(D)程式重點分析:

(1) 28~41 二分搜尋演算法

(2) 29 low=0; high=49;設定原陣列搜尋範圍。

(3) 30 flag=0。設定搜尋旗號為否(還未找到)。

(4) 31~41 while((low+1) < high) { ….}。其中 (low+1) < high 表示元素較高的指標 high 還是高於較低的 low,則陣列還未搜尋完畢。

(5) 32 mid = (high + low)/2。陣列元素索引 high low 之間的中間元素的索引 mid

(6) 33 if(value == a[mid] { …}。成立的話,表示找到該資料,則設定旗號並中斷離開。

(7) 37 else if (value > a[mid][0]) { …}。如未找到,但比中間值 a[mid] 大的話,則設定搜尋後半段(low = mid,但 high 未改變)。

(8) 39 else high = mid。都不是的話,則設定搜尋前半段(low 未改變)。

4-3-4 範例研討:有序陣列插入元素

(A)程式功能Ex4_4.java

吾人希望建立一個可供插入元素的有序陣列,其功能如下:

(1) 具有顯示陣列內容與插入元素的選項,選單如下:

D:\Java2_book\chap4>javac Ex4_4.java

 

D:\Java2_book\chap4>java Ex4_4

== 歡迎光臨 有序陣列管理系統 ==

(1) 列印有序陣列內容

(2) 插入陣列元素

(3) 離開系統

         請輸入工作選項 =>

(2) 當選擇顯示陣列內容(選擇 1),如下:

         請輸入工作選項 =>1

 

== 目前序陣列有 30 筆資料 ==

 2   4   6   8  10  12  14  16  18  20

22  24  26  28  30  32  34  36  38  40

42  44  46  48  50  52  54  56  58  60

(3) 插入元素(選擇 2),如下: (插入元素 15後,再顯示陣列內容)

         請輸入工作選項 =>2

請輸入欲插入元素 =>15

== 歡迎光臨 有序陣列管理系統 ==

(1) 列印有序陣列內容

(2) 插入陣列元素

(3) 離開系統

         請輸入工作選項 =>1

 

== 目前序陣列有 31 筆資料 ==

 2   4   6   8  10  12  14  15  16  18

20  22  24  26  28  30  32  34  36  38

  • 42  44  46  48  50  52  54  56  58

60

(B)系統分析

如欲將元素插入有序陣列內,必須搜尋出他適當的位置再插入,才會保持原來有序排列。以圖 4-9 為例,有序陣列 num={2, 5, 10, 23, 34},並以 point=4 表示目前游標在 4。如欲插入 8 的話,則必須將大於 8 的元素往後移一位,再將 8 插入。

4-9 有序陣列插入元素

插入的運作程序如圖 4-10 所示。首先將游標加一(移一位的意思),並將目前由標位置存入 k,如果 k 沒有大於0,表示是存入陣列第一筆資料。如果 k 大於 0,則比較數值是否大於欲插入的元素,如果大於的話,則往上移,否則就存入該空間。

4-10 有序陣列插入元素

(C)程式範例:Ex4_4.java

程式架構如圖 4-11 所示,在 Ex4_4.class 類別內包含 5 個元件,其中兩個類別變數,與 3 個方法程式。

4-11 Ex4_4 程式架構

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

//Ex4_4.java

/* 有序陣列的插入元素 */

 

import java.util.*;

public class Ex4_4{

  static int num[] = new int[50];     // 宣告陣列空間

  static int point;                   // 宣告游標變數

  public static void main(String args[]) {

      Scanner keyin = new Scanner(System.in);

      point = -1;      // 游標初值

      int select, k, item;

      for (int i=0; i< 30; i++){        //給予陣列初值

          num[i] = (i+1) *2;           //存入有序資料

          point = point + 1;           //游標指示目前位置

      }

      disp_menu();

      select = keyin.nextInt();

      while(select != 3) {

          switch(select) {

             case 1:

                  disp_array();

                  break;

             case 2:

                  if (point >=50) {

                      System.out.printf("陣列已滿無法插入!!\n");

                  }else {

                       System.out.printf("請輸入欲插入元素 =>");

                       item = keyin.nextInt();

                       point = point +1;

                       k = point;

                       while (true) {

                          if(num[k-1] > item) {

                              num[k] = num[k-1];

                              k = k - 1;

                          }

                          else {

                              break;

                          }

                          num[k] = item;

                       }

                   }

                   break;       

             default:

                 System.out.printf("輸入錯誤 !! 請重新輸入\n");

          }

          disp_menu();

          select = keyin.nextInt();

      }

 

   }

// 列印功能表

   static void disp_menu() {

       System.out.printf("== 歡迎光臨 有序陣列管理系統 ==\n");

       System.out.printf("(1) 列印有序陣列內容\n");

       System.out.printf("(2) 插入陣列元素\n");

       System.out.printf("(3) 離開系統\n");

       System.out.printf("\t 請輸入工作選項 =>");

   }

// 列印陣列內容

  static void disp_array() {     

      System.out.printf("\n== 目前序陣列有 %d 筆資料 ==\n", point+1);   

      for(int i=0; i<=point; i++) {

           System.out.printf("%2d  ", num[i]);

            if((i+1) % 10 == 0)

               System.out.printf("\n");    //列印五筆, 換行

      }

      System.out.printf("\n");           // 列印完畢, 換行

   }

}

4-3-5 自我挑戰:有序陣列元素處理

(A)程式功能:PM4_2.java

吾人希望由 Ex4_4 中擴充可以刪除元素的功能,如下:

(1)具有顯示陣列內容、插入與刪除元素的選項,選單如下:

D:\Java2_book\chap4>javac PM4_2.java

 

D:\Java2_book\chap4>java PM4_2

== 歡迎光臨 有序陣列管理系統 ==

(1) 列印有序陣列內容

(2) 插入陣列元素

(3) 刪除陣列元素

(4) 離開系統

         請輸入工作選項 =>

(2)當選擇顯示陣列(選擇 1),如下:

         請輸入工作選項 =>1

 

== 目前序陣列有 30 筆資料 ==

 2   4   6   8  10  12  14  16  18  20

22  24  26  28  30  32  34  36  38  40

44  46  48  50  52  54  56  58  60

(3)刪除元素(選擇 3),如下: (刪除元素 14 後,再顯示陣列內容)

         請輸入工作選項 =>3

請輸入欲刪除元素 =>14

== 歡迎光臨 有序陣列管理系統 ==

(1) 列印有序陣列內容

(2) 插入陣列元素

(3) 刪除陣列元素

(4) 離開系統

         請輸入工作選項 =>1

 

== 目前序陣列有 29 筆資料 ==

 2   4   6   8  10  12  16  18  20  22

24  26  28  30  32  34  36  38  40  42

 46  48  50  52  54  56  58  60

(B)系統分析

有序陣列刪除元素的運作程序幾乎與無序陣列相同,如圖 4-12 所示。首先找到欲刪除的元素,再將該元素後面的元素往前移一位 (num[i] = num[i+1]),再將游標減一(point = point -1) 即可。

4-12 有序陣列刪除元素的運作

(C)程式提示

4-13 PM4_2.java 的程式架構,包含 2 個類別變數與 4 個方法程式,其中 Binary_search() 是讓我們快速找到欲刪除元素的位置,找到後,後面的元素往前移一位即可。

4-13 PM4_2 程式架構

程式片段如下:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

import java.util.*;

public class PM4_2{

….

      while(select != 4) {

          switch(select) {

             …..

             …..

              case 3:

                  System.out.printf("請輸入欲刪除元素 =>");

                  item = keyin.nextInt();

                  int location = Binary_serach(item);

                  if (location == -1){

                        System.out.printf("陣列內沒有 %d 元素\n", item);

                  }else {

                     for(int i = location;i<=point;i++)

                         num[i] = num[i+1];

                  }

                  point = point - 1;

                  break;       

             default:

                 System.out.printf("輸入錯誤 !! 請重新輸入\n");

          }

           …….

      }

…..

//二分搜尋法

   static int Binary_serach(int value){

      int location=-1;       // 設定找到位置

      ….

      請參考 Ex4_3 二分搜尋法

      ….

     return location;

   }

}

翻轉工作室:粘添壽

 

Java 程式設計(二) 含物件導向

 

 

翻轉電子書系列: