第8章 列舉器與集合 注意: 本投影片僅供本書上課教師使用,非經同意請勿上網轉載或供拷貝
第八章 列舉器與集合 8.1 使用列舉器瀏覽陣列內容 8.2 集合類別 8.3 泛型與非泛型集合類別實作
8.1 使用列舉器瀏覽陣列內容 資料結構是資料在電腦中的儲存和組織方式。 設計程式時可依資料特性 選擇合適資料結構,以得到高效率處理。 8.1 使用列舉器瀏覽陣列內容 資料結構是資料在電腦中的儲存和組織方式。 設計程式時可依資料特性 選擇合適資料結構,以得到高效率處理。 由於資料結構在電腦進行大量資料處理時 地位重要 目前程式語言執行環境標準程式庫中都支援 多種資料結構。如: C++ 標準程式模板庫中的容器、 Java集合框架 微軟 .NET Framework 都支援。
8.1 使用列舉器瀏覽陣列內容 Continue … 常用資料結構: 陣列、串列(List)、堆疊(Stack)、佇列(Queue)、 鏈結串列(Linked List)、樹(Tree)、圖形(Graph) 和雜湊表(Hashtable) 即C# Dictionay。 以上資料結構內部實作與外部使用介面各有不同, 基本上都希望能提供走訪資料的能力。 走訪(Traverse) 能逐一瀏覽該資料結構內所有元素或稱節點。 譬如:串列走訪是從第一個節點開始,一直到 走訪到最後一個節點,每個節點都有走訪到。
8.1 使用列舉器瀏覽陣列內容 Continue … Enumerator 介面 支援非泛型集合簡單反覆運算。用於逐一查看集合 是所有非泛型列舉值的基底介面。 任何實作此類別物件才能用 foreach 來列舉讀取 集合中的元素,但無法用來修改基礎集合。 foreach 敘述可對物件的每個屬性或陣列/集合 的每個元素,逐一執行一個或多個敘述。
8.1 使用列舉器瀏覽陣列內容 Continue … foreach 敘述會隱藏列舉值的複雜度, 建議使用 foreach 而不直接使用列舉值。 foreach 是取得物件列舉器(Enumeraor), 透過呼叫列舉器的下列方法和屬性來存取 集合內的元素。 IEnumerator 介面包含兩個方法及一個屬性: 1. MoveNext() 方法 2. Current 屬性 3. Reset()方法
8.1 使用列舉器瀏覽陣列內容 Continue … 任何物件都必須實作 IEnumerator 和 IEnumerable 的兩個介面。 IEnumerable(可列舉的) 是用來瀏覽集合內容的介面,透過 GetEnumerator() 方法傳回 IEnumerator 的具備迭加器(Iterator)特性 的瀏覽物件。 IEnumerator(列舉器) 是用來取得集合的元素,需實作 兩個公開(用)的方法:MoveNext() 和 Reset() 一個公開(用)屬性 : Current。
8.1 使用列舉器瀏覽陣列內容 Continue … System.Collections 命名空間提供 GetEnumerator() 來走訪顯示集合物件內的元素。 程式中使用此方法必須引用下列命名空間 using System.Collections 譬如:巡訪 myAry 陣列內所有陣列元素內容。
參閱 P 8-4頁
參閱 P 8-5頁
參閱 P 8-6頁
8.2 集合類別 使用陣列缺點 呈線性排列存放在連續記憶體空間 插入或刪除陣列元素牽一髮動全身 改變陣列大小,須新建新陣列 8.2 集合類別 使用陣列缺點 呈線性排列存放在連續記憶體空間 插入或刪除陣列元素牽一髮動全身 改變陣列大小,須新建新陣列 .NET Framework 的 System.Collections 命名空間 提供Collection類別 Collection 類別其主要功能 將儲存的資料以某種資料結構組成 再以特定方式來走訪或稱巡訪資料,提高資料存取效率。 Collection 類別內的元素的型別都是物件 集合類別內元素的存取都以物件方式進行。
比較整數陣列和物件陣列兩者在記憶體配置上差異
8.3 泛型與非泛型集合類別實作 泛型(Generic) 為 NET Framwork 引入的型別參數 (Type Parameter) 概念。 使用時機 型別參數是在設計類別和方法時,無法知道使用者會使用 哪種資料型別的參數,可能是 string 或 int ? 若使用泛型就不用擔心程式被呼叫時,需考慮傳入的資料 型別,只要專心開發功能。 若用型別參數T寫一個名稱為 List1<T> 的 List串列集合類別 可用List1<int>、List1<string>、List1<myClass> 可避免進行型別轉換或裝箱(Boxing) 操作的代價和風險。
8.3 泛型與非泛型集合類別實作 Continue… 泛型類別和泛型方法具重複性、型別安全和高效率, 不是非泛型集合類別所能及。 泛型廣泛應用於集合和對集合操作的方法中。 泛型和非泛型集合類別在觀念和功能上差異 非泛型集合類別在取值時需做型別轉換工作, 當集合的元素為實值型別會引起 Boxing 和 Unboxing 動作 使用泛型集合可得到型別安全的好處, 不需衍生自基底集合型別及實作型別特定的成員。 Boxing 處理 是將實值型別轉換成 object 型別,或任何由這個 實值型別實作的介面型別。 Unboxing 處理:會從物件擷取實值型別。
8.3 泛型與非泛型集合類別實作 Continue… 當集合內的元素為實值型別時 泛型集合型別比非泛型集合型別有較理想效能, 也優於衍生自非泛型基底集合型別的型別 泛型不需將這些元素進行 Boxing 處理。 泛型類別和方法將 重複使用性、型別安全 和 高效率 結合一起,發揮非泛型類別和方法無法 提供的功能。 泛型最常搭配在某種指定型別上操作的集合和 方法使用。 VS 2005 開始使用 C# 2. 0版,C# 提供泛型新功能,
8.3 泛型與非泛型集合類別實作 Continue… 在 .NET Framework 2.0 類別庫中的 System. Collections.Generic 命名空間 才支援 泛型 功能。 該命名空間包含多個以泛型為基礎的新集合類別, 該命名空間包含會定義泛型集合的介面和類別 讓使用者建立 強化型別(Stronged Type)的集合, 提供比非泛型強化型別集合使用的命名空間 System.Collections 有更佳的型別安全和效能。
8.3 泛型與非泛型集合類別實作 Continue… .NET Framework 內提供用於存取資料的特製化類別 這些類別可支援堆疊、佇列、清單和雜湊資料表)。 大部分的 Collection類別都會實作相同的介面, 這些介面可加以繼承來建立新的Collection類別,符合進 一步的特定資料儲存需求。 非泛型集合類別定義於 System.Collections 命名空間包括: ArrayList、Stack、Queue、Hashtable、 SortedList 。 泛型集合主要定義於 System. Collections.Generic 命名空間 包括: List<T>、LinkedList<T>、Stack<T>、Queue<T>、 Dictionary<TKey,TValue>、SortedList<TKey,TValue>等 集合類別。
8.3 泛型與非泛型集合類別實作 Continue… 目前 Visual Studio 已升級至VS 2013,提供的 .NET Framework 升級到4.5.1版,C# 到5.0版。 若使用 .NET Framework 2.0 (含)以後版本來開發 應用程式,建議使用System.Collections.Generic 命名空間中 的泛型集合類別比使用System. Collections 命名空間中的非泛 型的對應的集合類別有更好的型別安全和效率。 大部分集合類別都衍生自 ICollection、IComparer、 IEnumerable、IList、IDictionary 和 IDictionary Enumerator 等介面及其泛型對等用法。 泛型集合類別除提供更高型別安全外,且在某些情況, 尤其在儲存實值型別時,可提供更佳效能。
一. ArrayList 與 List<T> 集合類別實作 可解決上述一般陣列插入、刪除、複製元素 所發生的問題。 兩者 Collection 類別提供下列屬性方法 讓你能靈活操作串列:
常用屬性與方法完整範例程式檔名: c08/aryList1/aryList1. sln ch08/aryList2/aryList2 常用屬性與方法完整範例程式檔名: c08/aryList1/aryList1.sln ch08/aryList2/aryList2.sln。 輸出結果:
一. ArrayList 與 List<T> 集合類別實作 Contiune… 陣列內的所有陣列元素的資料型別要相同。 ArrayList 和 List都屬串列,串列內允許存放 不同資料型別的元素。 串列可用註標,指向串列中某個元素。 透過 foreach 反複運算來走訪列內所有元素。 若串列內元素的資料型別不一致,foreach 內的 資料型別必須設為 Object 若串列內都是字串,設為 string 若串列內都是整數,設為int … 以此類推。
一. ArrayList 與 List<T> 集合類別實作 Contiune… ArrayList 串列集合類別的定義和宣告置於 System.Collections 命名空間內 List串列集合類別的定義和宣告置於 System.Collections.Generic 命名空間內 寫法: using System.Collections ; 使用ArrayList 串列 using System.Collections.Generic 使用List<T> 串列
二. Stack 與 Stack<T>集合類別 採後進先出(Last In First Out : LIFO)的機制。 串列加入資料(Push) 和移出資料(Pop)都從堆疊 最上面,像廚房裡成疊盤子。 堆疊如一個有底袋子,元素存取只有最上面一個 開口。
二. Stack 與 Stack<T>集合類別 Continue… 製作非泛型堆疊集合類別和泛型堆疊集合類別的 定義和宣告分別置於 System. Collections 命名空間 和 System.Collections.Generic命名空間內 程式有使用到該類別,須在程式開頭用 using 引用 對應的命名空間: 使用Stack 非泛型堆疊 using System.Collections ; 使用Stack<T> 泛型堆疊 using System.Collections.Generic ;
常用屬性與方法完整範例程式檔名: ch08/Stack0/Stack0.sln
三. Queue與Queue<T>集合類別 採先進先出(First In First Out : FIFO)的機制。 加入資料(EnQueue) 從串列的最後面 取出資料(DeQueue) 從串列另一端最前開始移出。 佇列如兩邊都有開口的袋子,最早置入的資料, 最早移出;最晚置入的資料,最晚移出。
三. Queue與Queue<T>集合類別 Continue… 製作非泛型佇列集合類別和泛型佇列集合類別 的定義和宣告分別置於 System. Collections 命名空間 和 System.Collections.Generic命名空間內, 程式有使用到該類別,分別在程式開頭用 using 來引用對應的命名空間: 使用Queue 非泛型佇列 using System.Collections ; 使用Queue<T> 泛型佇列 using System.Collections.Generic
四. Hashtable與Dictionary<TKey, TValue>集合類別 陣列 和 ArrayList 串列 把整數註標值置於中括號內來存取對應的一個元素。 關聯陣列(Associative Array) 需用整數以外的資料型別來當註標值。 Hashtable(雜湊表)類別屬非泛型類別 是 System.Collections 命名空間提供的一個容器, 在 Hashtable 內含兩個物件陣列: 一個含有對應索引鍵(Key)當註標 一個含有對應值(Value) 將Key & Value(鍵/值對)置入 Hashtable內會自動維護 以Key & Value 對應關係,使得 Hashtable 具有以 key 直接走訪 Value 的索引方式,加快尋找的速度。
四. Hashtable與Dictionary<TKey, TValue>集合類別 Hashtable 的 key/value 均為 object, Hashtable 可支援任何類型的 Key & Value。 程式中用到此類別須在程式開頭 用using 引用 System.Collections 命名空間 Dictionary 屬泛型類別,型式為 Dictionary<TKey, TValue>, 含有TKey、TValue 兩個具任何資料型別型別引數。 Dictionary 和HashTable類別一樣提供一組索引鍵(key) 和一組值(value) 加入 Dictionary類別物件中的每個項目都是由其關聯索引鍵 和值所組成。使用其索引鍵擷取值的速度快。
四. Hashtable與Dictionary<TKey, TValue>集合類別 Dictionary <TKey, TValue> 中每個索引鍵都必須是唯一 且也不能是 null。 Dictionary 泛型類別物件的屬性及方法使用方式和 Hashtable雜湊表集合類別物件相近。 Dictionary<TKey,TValue>類與 Hashtable 類別的功能相同。 由於 Hashtable 的元素屬 Obhject 類型,在儲存或檢索值 類型時通常發生裝箱和取消裝箱操作。 大量資料插入時需花比Dictionary多時間, 以for 迴圈方式可快速走訪 Hashtable 和 Dictionary。 以 foreach 方式走訪,Dictionary走訪速度會更快。
四. Hashtable與Dictionary<TKey, TValue>集合類別 製作非泛型 Hashtable 集合類別和泛型 Dictionary 集合類別的定義和宣告分別置於 System.Collections 命名空間和 System.Collections.Generic命名空間內, 程式中若有使用到該類別,必須分別在程式開頭使 用using 來引用對應的命名空間: 使用Hashtable 非泛型雜湊表 using System.Collections ; 使用Dictionary<T> 泛型字典 using System.Collections.Generic
五. SortedList 與 SortedList<TKey, TValue>集合類別 SortedList串列和Hashtable都屬Key&Value(鍵-值)組合。 Hashtable 介紹的屬性和方法都可在 SortList 串列中使用, 走訪 SortedList 串列內的元素需指定對應索引鍵 , 兩者主要差異在將 Key&Value 組合置入 SortedList串列, 會先排序對應索引鍵,在對應鍵陣列中找到正確位置後, 才將對應值置入對應值陣列中相同對應位置。 對 SortedList 串列做新增或移除動作,鍵-值組合都會保持 同步。 要注意 SortedList串列和Hashtable 都不允許有重複對應 索引鍵。 使用 foreach重複操作同樣會得到 DictionaryEntry物件, 且DictionaryEntry 的順序是排序後的結果。
範例 先建立SortedList非泛型串列,分別對SortedList 串列做新增、查詢和刪除動作,並分別使用for 和 foreach 迴圈操作來顯示目前 SortedList串列內所有 元素。 下表為 Hashtable使用Key&Value 的Apple單價表 :
程式碼 參閱 P 8-26 頁
本章結束 …