• 沒有找到結果。

主題 12:集合 (Collection)

在文檔中 正修科技大學資訊工程系 (頁 23-33)

}

範例 11_泛型_04_限定的泛型 public class Ch04 {

public static void main(String args[]) {

//宣告與產生物件實體時,同時指定泛型的真實資料型態

MyClass<String,Integer> obj=new MyClass<String,Integer>();

System.out.println("在中間的是: "+obj.mid("哈囉","你好","!"));

System.out.println("在中間的是: "+obj.mid(1,2,3));

//System.out.println("在中間的是: "+obj.mid(1,2,"你好"));

} }

//宣告兩個泛型名稱,T1將來可以是任何的資料型態,但T2只能是Number類別的子孫類別型態,如Integer、Float等 class MyClass<T1,T2 extends Number>

{

T1 mid(T1 a, T1 b, T1 c) {

return b;

}

T2 mid(T2 a, T2 b, T2 c) {

return b;

} }

主題 12:集合 (Collection)

Collection 可以翻譯為集合,是將多個元素組織為一個單元的抽象設計方式。

Collection 有時也被稱為集合物件或容器,指一群相關聯的資料集合在一起組成一個物件。而集合物 件裡的資料,稱為元素。我們可以運用集合物件儲存、取用或操作資料(新增、刪除、排序等),或 將資料從一個方法傳遞到另一個方法。

至於要使用什麼樣的容器則依設計需求而定,可以使用循序有索引的 List 結構、不允許重複元素的 Set 結構、或是「鍵-值」(Key-Value)索引的 Map 結構來儲存資料。

Java Collections Framework 主要分為兩大繼承族譜,一類為 Collection 介面的子孫介面,另一類為 Map 介面的子孫介面。其中,Collection 介面一系代表的是單一元素系,而 Map 介面一系代表的是 Key-Value 的成對(pair)元素系。

首先介紹幾個主要介面的特性:

- Collection 介面

可以將此介面視為單一元素的集合,並未規定元素在集合內是否允許重複,也未規定是否具有順序,

進階的規定交由繼承的子介面來規範。

-Set 介面

其內不能有重複的元素,但元素的順序未加以規定,類似於數學上的集合。

-SortedSet 介面

繼承自 Set 介面,並且要求其內的元素會自動遞增排序,譬如英漢字典裡的單字排序就符合此介面 的規範。

-List 介面

其內可以有重複的元素,且元素在集合裡是有順序性的(物件加入容器的順序),每個元素都有其對 應的位置(數值的索引),可以透過位置來存取元素,譬如陣列(Array)就符合此介面的規範。

-Queue 介面

其內元素的取出具有一定的順序,即符合先進先出(first-in first-out)的原則。

-Map 介面

此介面為成對(pair)之集合,每個元素由兩個值組成,一個為 key 另一個為 value。此外,key 值是 不能重複的,且每個 key 只能映射(mapping)到一個 value,但每個 value 則不限定幾個 key 來對應。

每個元素必須同時有 key 與 value,成對表現才具意義。

-SortedMap 介面

繼承自 Map 介面,規定其內的元素必須按照 key 值自動排序。譬如成績單若依學號來排序,即符合 此介面的規範。

接下來介紹幾個常見的集合介面實作:

-HashSet 類別(Set 介面的實作)

HashSet 在實作時,採用資料結構中雜湊表(Hash Table)的方式來完成,元素的順序與存入時的順序 無關。HashSet 根據湊雜碼來確定元素於容器中儲存的位置,也根據雜湊碼來快速的找到容器中的元 素,在大多數情況下這樣的方式可以有效提升搜尋、新增、刪除元素的速度。

-TreeSet 類別(Set 介面或 SortedSet 的實作)

TreeSet 使用的是紅黑樹(Red-black tree)的資料結構來實作。每次有資料加進去,就會對資料作排序

(遞增)。

-ArrayList 類別(List 介面的實作)

ArrayList 使用陣列結構來實作,元素加入時是用索引值(index)依序儲存。陣列的特性是依據索引 來快速指定物件的位置,所以對於快速的隨機取得物件來說,使用 ArrayList 可以得到較好的效能,

但由於使用陣列實作,若要從中間作移除或插入物件的動作,會需要搬動後段的陣列元素以重新調整 索引順序,所以速度上就會慢的多。

-LinkedList 類別(List 介面與 Deque 介面的實作)

LinkedList 使用鏈結串列(Linked list)的資料結構來實作。鏈結串列是由許多節點(node)所構成的 串列(list),每個節點包含資料欄位與鏈結欄位,透過鏈結欄位指向下一個節點的位址,至於最後一 個節點的鏈結欄位則指向 null,代表串列已經結束。

鏈結串列在刪除或插入節點時,是透過改變鏈結欄位的方式達成,不必如同陣列般進行資料的大量搬 移,因此如果元素在加入之後大都是為了取出,而不會常作移除或插入的動作,建議使用 ArrayList 效 能上會比較好;但如果需要經常從容器中作移除或插入元素的動作,則使用 LinkedList 會獲得較好 的效能。

-HashMap 類別(Map 介面的實作)

HashMap 使用雜湊表結構來實作,儲存的元素分為 key 值與 value 值,形成一個 key-value pair,使 我們能依據 key 值快速查找到對應的資料。

-TreeMap 類別(Map 介面與 SortedMap 介面的實作)

TreeMap 使用紅黑樹結構來實作,儲存的元素同樣分為 key 值與 value 值,元素會依據 key 值由小 至大排序。

範例 12_集合_01_HashSet import java.util.HashSet;

public class Ch01 {

public static void main(String[] args) {

HashSet<String> color=new HashSet<String>(); //宣告一名為 color 的 HashSet 集合物件, 集合內元素 的型態為 String

String str1="green",str2="yellow";

System.out.println("color empty: "+color.isEmpty());

color.add("blue"); //新增元素 color.add("red");

color.add(str1);

color.add(str2);

System.out.println("新增重複元素: "+color.add("blue")); //若成功會回傳true System.out.println("color empty: "+color.isEmpty()); //集合是否為空

System.out.println("color size: "+color.size()); //集合大小 (元素數量) System.out.println("color 內容: "+color); //集合內容

color.remove(str1); //移除元素 System.out.println("color size: "+color.size());

System.out.println("color 內容: "+color);

System.out.println("color 中是否有 str1: "+color.contains(str1)); //是否包含元素 System.out.println("color 中是否有 blue: "+color.contains("blue"));

color.add("pink");

System.out.println("color 內容: "+color);

color.clear(); //清除集合中所有元素 System.out.println("color empty: "+color.isEmpty());

System.out.println("color 內容: "+color);

System.out.println("color size: "+color.size());

} }

範例 12_集合_02_TreeSet import java.util.TreeSet;

public class Ch02 {

public static void main(String[] args) {

TreeSet<Integer> n=new TreeSet<Integer>();

for(int i=20; i>=2; i-=2) n.add(i);

System.out.println("元素個數: "+n.size());

System.out.println("集合內容: "+n);

System.out.println("第一個元素: "+n.first());

System.out.println("最後一個元素: "+n.last());

System.out.println("介於6和14之間的集合: "+n.subSet(6, 14));

System.out.println("大於等於10的集合: "+n.tailSet(10));

System.out.println("小於8的集合: "+n.headSet(8));

} }

範例 12_集合_03_ArrayList import java.util.ArrayList;

public class Ch03 {

public static void main(String[] args) {

ArrayList<Integer> n=new ArrayList<Integer>(); //可將 ArrayList 集合視為可變更大小的動態陣列 for(int i=20; i>=2; i-=2)

n.add(i);

n.add(40);

n.add(60); //以上所加入的元素將依據加入的順序排列 n.add(0, 80); //指定索引值為 0 加入元素

n.add(1, 100);

System.out.println("元素個數: "+n.size());

System.out.println("集合內容: "+n);

n.add(1, 150); //插入點後的所有元素其索引值都會改變 System.out.println("集合內容: "+n);

n.set(2, 10); //將索引值 2 的元素以 10 取代 System.out.println("集合內容: "+n);

n.remove(3); //移除索引值為 3 的元素 System.out.println("集合內容: "+n);

System.out.println(n.indexOf(10)); //第一個元素值為 10 的索引值

System.out.println(n.lastIndexOf(10)); //最後一個元素值為 10 的索引值 (由後往前搜尋第一個)

System.out.println(n.get(1)); //集合中索引值為 1 的元素 }

}

範例 12_集合_04_LinkedList import java.util.LinkedList;

public class Ch04 {

public static void main(String[] args) {

//LinedList 和 ArrayList 其實很像,多了處理 LinkedList<Integer> n=new LinkedList<Integer>();

for(int i=20; i>=2; i-=2) //元素將以加入的順序排列 n.add(i);

n.addFirst(10); //加入一個元素在鏈結串列的最前方 n.addLast(10); //加入一個元素在鏈結串列的最後方 n.addFirst(100);

System.out.println("元素個數: "+n.size());

System.out.println("集合內容: "+n);

n.removeFirstOccurrence(10); //移除第一個值為 10 的元素 n.removeLastOccurrence(10); //移除最後一個值為 10 的元素 System.out.println("集合內容: "+n);

n.removeFirst(); //移除鏈結串列中最前方的元素

n.removeLast(); //移除鏈結串列中最後方的元素 System.out.println("集合內容: "+n);

System.out.println(n.get(1)); //鏈結串列中索引值為 1 的元素 System.out.println(n.getFirst()); //鏈結串列中最前方的元素

System.out.println(n.getLast()); //鏈結串列中最後方的元素

System.out.println(n.indexOf(18)); //第一個元素值為 18 的索引值

System.out.println(n.lastIndexOf(18)); //最後一個元素值為 18 的索引值 (由後往前搜尋第一個)

System.out.println(n.indexOf(30)); //若回傳 -1 代表找不到該元素 }

}

範例 12_集合_05_HashMap import java.util.HashMap;

import java.util.Set;

import java.util.Collection;

public class Ch05 {

public static void main(String[] args) {

HashMap<Integer,String> hm=new HashMap<Integer,String>();

hm.put(92001, "Ben");

hm.put(92002, "Peter");

hm.put(92003, "Tony");

System.out.println("HashMap 是否為空: "+hm.isEmpty());

System.out.println("元素個數: "+hm.size());

System.out.println("HashMap 的內容: "+hm);

System.out.println("HashMap 中是否有關鍵值為 92001 的元素: "+hm.containsKey(92001));

System.out.println("HashMap 中是否有對應值為 Kevin 的元素: "+hm.containsValue("Kevin"));

hm.put(92001, "John"); //覆蓋舊值

System.out.println("HashMap 的內容: "+hm);

hm.remove(92002); //移除關鍵值為 92002 的元素 System.out.println("HashMap 的內容: "+hm);

System.out.println("關鍵值 92003 的對應值: "+hm.get(92003));

Set<Integer> id=hm.keySet(); //將各元素的 K 欄位集合轉換為 Set 物件 System.out.println("ID 集合內容為: "+id);

Collection<String> name=hm.values(); //將各元素的 V 欄位集合轉換為 Collection 物件 System.out.println("姓名集合內容為: "+name);

} }

範例 12_集合_06_TreeMap import java.util.TreeMap;

public class Ch06 {

public static void main(String[] args) {

TreeMap<Integer,String> tm=new TreeMap<Integer,String>();

tm.put(92001, "Ben");

tm.put(92002, "Peter");

tm.put(92003, "Tony");

System.out.println("TreeMap 是否為空: "+tm.isEmpty());

System.out.println("元素個數: "+tm.size());

System.out.println("TreeMap 的內容: "+tm); //依 key 值遞增排序

System.out.println("TreeMap 中是否有關鍵值為 92001 的元素: "+tm.containsKey(92001));

System.out.println("TreeMap 中是否有對應值為 Kevin 的元素: "+tm.containsValue("Kevin"));

System.out.println("第一個元素為: "+tm.firstKey()+" "+tm.get(tm.firstKey()));

System.out.println("最後一個元素為: "+tm.lastKey()+" "+tm.get(tm.lastKey()));

System.out.println("關鍵值大於或等於 92002 的元素: "+tm.tailMap(92002));

System.out.println("關鍵值大於或等於 92002 且小於 92003 的元素: "+tm.subMap(92002,92003));

} }

再接著我們介紹 Iterator 與 ListIterator 介面:

Iterator 與 ListIterator 介面,可用來「走訪」或是刪除集合物件的元素。Iterator 物件的讀取是單向的,

且只能讀取一次;而 ListIterator 物件的走訪可以是雙向的(正向、反向)。

範例 12_集合_07_Iterator 介面 import java.util.TreeSet;

import java.util.Iterator;

public class Ch07 {

public static void main(String[] args) {

TreeSet<Integer> ts=new TreeSet<Integer>();

for(int i=20; i>=2; i-=2) ts.add(i);

System.out.println("元素個數: "+ts.size());

System.out.println("集合內容: "+ts);

Iterator<Integer> itr=ts.iterator(); //將 TreeSet 集合物件轉換為 Iterator 物件 System.out.print("正向走訪: "); //只能讀取一次

while(itr.hasNext()) //若仍有下個元素則回傳 true System.out.print(itr.next()+" "); //回傳下個元素 System.out.println();

itr.remove(); //移除最後讀取的元素 System.out.println("集合內容: "+ts);

} }

範例 12_集合_08_ListIterator 介面 import java.util.LinkedList;

import java.util.ListIterator;

public class Ch08 {

public static void main(String[] args) {

LinkedList<Integer> ts=new LinkedList<Integer>();

for(int i=20; i>=2; i-=2) ts.add(i);

System.out.println("元素個數: "+ts.size());

System.out.println("集合內容: "+ts);

ListIterator<Integer> itr1=ts.listIterator(); //將 LinkedList 集合物件轉換為 ListIterator 物件

ListIterator<Integer> itr2=ts.listIterator(ts.size()); //將 LinkedList 集合物件轉換為 ListIterator 物件, 並指 定指標位置(介於元素之間)

System.out.print("正向走訪: "); //只能讀取一次 while(itr1.hasNext()) //若仍有下個元素則回傳 true

System.out.print(itr1.next()+" "); //回傳下個元素 System.out.println();

System.out.print("反向走訪: "); //同樣只能讀取一次 while(itr2.hasPrevious()) //若仍有下個元素則回傳 true

System.out.print(itr2.previous()+" "); //回傳下個元素 System.out.println();

itr2.remove(); //移除最後讀取的元素 System.out.println("集合內容: "+ts);

} }

最後介紹 Collections 類別:

Collections 類別是 Java Collections Framework 中專門負責演算法的類別。該類別中提供了多個有用的 static 方法,較常用的有 binarySearch()、copy()、max()、min()、reverse()、sort()、swap() 等。

範例 12_集合_09_Collections 類別 import java.util.Collections;

import java.util.HashSet;

public class Ch09 {

public static void main(String[] args) {

HashSet<Integer> hs=new HashSet<Integer>();

hs.add(11);

hs.add(8);

hs.add(2);

hs.add(33);

hs.add(29);

System.out.println("集合內容: "+hs);

System.out.println("集合中最大的數: "+Collections.max(hs));

System.out.println("集合中最小的數: "+Collections.min(hs));

//Collections.sort(hs); //包含 sort(),reverse() 等多數 Collections 類別所提供的方法只適用 List 介面 的實作

} }

範例 12_集合_10_其他應用 1 import java.util.HashSet;

import java.util.TreeSet;

import java.util.LinkedList;

import java.util.Collections;

public class Ch10 {

public static void main(String[] args) {

HashSet<Integer> hs=new HashSet<Integer>();

//利用 HashSet 元素不得重複的特性, 產生不重複之隨機亂數 while(hs.size()<6) //當元素數量達到 6 時, 停止加入元素 {

//System.out.println(hs.add((int)(Math.random()*39+1)));

//若出現重複則會造成元素加入失敗, 並回傳 false hs.add((int)(Math.random()*39+1)); //1~39

}

System.out.println("本期樂透號碼: "+hs);

TreeSet<Integer> ts=new TreeSet<Integer>(hs); //將 HashSet 集合物件, 轉換為 TreeSet 集合物件 //TreeSet<Integer> ts=new TreeSet<Integer>();

//ts.addAll(hs);

System.out.println("本期樂透號碼: "+ts);

LinkedList<Integer> ll=new LinkedList<Integer>(hs); //將 HashSet 集合物件, 轉換為 LinkedList 集合物

System.out.println("本期樂透號碼: "+ll);

Collections.sort(ll);

System.out.println("本期樂透號碼: "+ll);

Collections.reverse(ll);

System.out.println("本期樂透號碼: "+ll);

} }

範例 12_集合_11_其他應用 2 //import java.util.Collections;

import java.util.LinkedList;

import java.util.ListIterator;

public class Ch11 {

public static void main(String[] args) { Stu stu1=new Stu(92001,"Tony",95);

Stu stu2=new Stu(92002,"Ben",80);

Stu stu3=new Stu(92003,"Peter",85);

Stu stu4=new Stu(92004,"May",75);

LinkedList<Stu> ll=new LinkedList<Stu>(); //元素為 Stu 物件 ll.add(stu1);

ll.add(stu2);

ll.add(stu3);

ll.add(stu4);

//System.out.println("集合內容: "+ll); //無法顯示 System.out.println("使用 for 迴圈正向走訪:");

for(Stu s:ll)

s.showProfile();

System.out.println();

ListIterator<Stu> itr=ll.listIterator();

System.out.println("使用 ListIterator 介面正向走訪:");

while(itr.hasNext()) {

itr.next().showProfile(); //itr.next() 所取出的元素為物件 }

//Collections.sort(ll); //集合內容為物件, 無法排序 }

} class Stu {

int id,score;

String name;

Stu(int id, String name, int score) {

this.id=id;

this.name=name;

this.score=score;

}

void showProfile() {

System.out.println("學號: "+id+"\t姓名: "+name+"\t成績: "+score);

} }

範例 12_集合_12_其他應用 3 import java.util.HashSet;

import java.util.HashMap;

public class Ch12 {

public static void main(String[] args) { int n[]={23,45,73,22,45};

for(int i:n) //for 迴圈針對 Collection 或 Array 的特殊寫法 System.out.print(i+" ");

System.out.println();

System.out.println();

在文檔中 正修科技大學資訊工程系 (頁 23-33)

相關文件