C# 泛型集合之非泛型集合類與泛型集合類的對應: ArrayList對應List HashTable對應Dictionary Queue對應Queue Stack對應Stack SortedList對應SortedList 第一 : ArrayList(非泛型集合) 與List(泛型集合) Arra ...
C# 泛型集合之非泛型集合類與泛型集合類的對應:
ArrayList對應List
HashTable對應Dictionary
Queue對應Queue
Stack對應Stack
SortedList對應SortedList
第一 : ArrayList(非泛型集合) 與List(泛型集合)
ArrayList 是數組的複雜版本。ArrayList 類提供在大多數 Collections 類中提供但不在 Array 類中提供的一些功能:
1.Array 的容量是固定的,而 ArrayList 的容量是根據需要自動擴展的。
2.ArrayList 提供添加、插入或移除某一範圍元素的方法。在 Array 中,您只能一次獲取或設置一個元素的值。
3.使用 Synchronized 方法可以很容易地創建 ArrayList 的同步版本。而 Array 將一直保持它直到用戶實現同步為止。
4.ArrayList 提供將只讀和固定大小包裝返回到集合的方法。而 Array 不提供。
5.Array 提供 ArrayList 所不具有的某些靈活性:
a.可以設置 Array 的下限,但 ArrayList 的下限始終為零。
b.Array 可以具有多個維度,而 ArrayList 始終只是一維的。
c.特定類型(不包括 Object)的 Array 的性能比 ArrayList 好,這是因為 ArrayList 的元素屬於 Object 類型,所以在存儲或檢索值類型時通常發生裝箱和取消裝箱。
d.要求一個數組的大多數情況也可以代之以使用 ArrayList。它更易於使用,並且通常具有與 Object 類型的數組類似的性能。
6.Array 位於 System 命名空間中;ArrayList 位於 System.Collections 命名空間中。
ArrayList類對象方法:
1:Add()向數組中添加一個元素,
2:Remove()刪除數組中的一個元素
3:(int i)刪除數組中索引值為i的元素
4:Reverse()反轉數組的元素
5:Sort()以從小到大的順序排列數組的元素
6:Clone()複製一個數組
一:ArrayList:
ArrayList可以不用指定維數 可動態賦值 賦不同類型值
ArrayList arrayList1 = new ArrayList(); arrayList1. arrayList1.Add("a"); arrayList1.Add(1); arrayList1.Add("b"); Response.Write(arrayList1[1]);
二:Array:
Array的容量是固定的 先指定大小 在賦值
Array arrayList2 = Array.CreateInstance(typeof(string), 6); arrayList2.SetValue("a", 0); arrayList2.SetValue("b", 1); Response.Write(arrayList2.GetValue(1));
List泛型集合:
泛型集合List<T>
泛型最重要的應用就是集合操作,使用泛型集合可以提高代碼重用性,類型安全和更佳的性能。
List<T>的用法和ArrayList相似,List<T>有更好的類型安全性,無須拆,裝箱。
在泛型定義中,泛型類型參數“<T>”是必須指定的,其中T是定義泛型類時的占位符,其並不是一種類型,僅代表某種可能的類型。在定義時T會被使用的類型代替。泛型集合List<T>中只能有一個參數類型,“<T>”中的T可以對集合中的元素類型進行約束。
eg:
List<T>添加、刪除、檢索元素的方法和ArrayList相似,明顯的特點是不需要像ArrayList那樣裝箱和拆箱。
List < Student > students = new List < Student > (); Student stu1 = new Student(); stu1.Name = "陸小鳳"; stu1.Number = "0801"; stu1.Score = 20; Student stu2 = new Student(); stu2.Name = "西門吹雪"; stu2.Number = "0802"; stu2.Score = 23; students.Add(stu1); students.Add(stu2); Console.WriteLine("集合中的元素個數為{0}", students.Count); foreach (Student stu in students) { Console.WriteLine("/t{0}/t{1}/t{2}", stu.Name, stu.Number, stu.Score); } students.Remove(stu1); Console.WriteLine("集合中的元素個數為{0}", students.Count); Console.ReadLine();
List<T>和ArrayList的區別
List<T>和ArrayList的相同點:添加元素、刪除元素、通過索引訪問元素方法相同。
List<T>和ArrayList的不同點:
ArrayList可以添加任意類型元素;List<T>對添加的元素具有類型約束;
ArratList添加時裝箱,讀取時拆箱;List<T>不需要裝箱,拆箱操作;
//創建Person對象 Person p1 = new Person("張三", 30); Person p2 = new Person("李四", 20); Person p3 = new Person("王五", 50); //創建類型為Person的對象集合 List < Person > persons = new List < Person > (); //將Person對象放入集合 persons.Add(p1); persons.Add(p2); persons.Add(p3); //輸出第2個人的姓名 Console.WriteLine(persons[1].Name); foreach (Person p in persons) { Console.WriteLine("/t{0}/t{1}", p.Name, p.Age); }
第二 :HashTable(非泛型集合)對應Dictionary(泛型集合)
Hashtable 和 Dictionary <K, V> 類型
1:單線程程式中推薦使用 Dictionary, 有泛型優勢, 且讀取速度較快, 容量利用更充分.
2:多線程程式中推薦使用 Hashtable, 預設的 Hashtable 允許單線程寫入, 多線程讀取, 對 Hashtable 進一步調用 Synchronized() 方法可以獲得完全線程安全的類型. 而 Dictionary 非線程安全, 必須人為使用 lock 語句進行保護, 效率大減.
3:Dictionary 有按插入順序排列數據的特性 (註: 但當調用 Remove() 刪除過節點後順序被打亂), 因此在需要體現順序的情境中使用 Dictionary 能獲得一定方便.
Hashtable 類和 Dictionary<(Of <(TKey, TValue>)>) 泛型類實現 IDictionary 介面
Dictionary<(Of <(TKey, TValue>)>) 泛型類還實現 IDictionary<(Of <(TKey, TValue>)>) 泛型介面。因此,這些集合中的每個元素都是一個鍵/值對。
Dictionary<(Of <(TKey, TValue>)>) 類與 Hashtable 類的功能相同
對於值類型,特定類型(不包括 Object)的 Dictionary<(Of <(TKey, TValue>)>) 的性能優於 Hashtable,這是因為 Hashtable 的元素屬於 Object 類型,所以在存儲或檢索值類型時通常發生裝箱和取消裝箱操作。
eg:
HashTable ht=new HashTable();//實現 IDictionary介面 ht.Add(1,"A"); ht.Add(2,"B"); ht.Add(3,"c"); foreach(DictionaryEntry de in ht)//HashTable返回的是DictionaryEntry類型 { de.Key; de.Value; } Dictionary<int,string> myDictionary=new Dictionary<int,string>();//實現IDictionary介面,IDictionary<T key,T value>類 myDictionary.Add(1,"a"); myDictionary.Add(2,"b"); myDictionary.Add(3,"c"); foreach(int i in myDictionary.Keys) { Console.WriteLine("Key="+i+"Value="+myDictionary); } Or foreach(KeyValuePair<string, double> temp in myDictionary)//返回的是KeyValuePair<string, double>泛型數組 { temp.Key; temp.Value; }
一:HashTable:
1.HashTable是一種散列表,他內部維護很多對Key-Value鍵值對,其還有一個類似索引的值叫做散列值(HashCode),它是根據GetHashCode方法對Key通過一定演算法獲取得到的,所有的查找操作定位操作都是基於散列值來實現找到對應的Key和Value值的。
2.我們需要使用一個演算法讓散列值對應HashTable的空間地址儘量不重覆,這就是散列函數(GetHashCode)需要做的事。
3.當一個HashTable被占用一大半的時候我們通過計算散列值取得的地址值可能會重覆指向同一地址,這就是哈希衝突。
4.在.Net中鍵值對在HashTable中的位置Position= (HashCode& 0x7FFFFFFF) % HashTable.Length,.net中是通過探測法解決哈希衝突的,當通過散列值取得的位置Postion以及被占用的時候,就會增加一個位移x值判斷下一個位置Postion+x是否被占用,如果仍然被占用就繼續往下位移x判斷Position+2*x位置是否被占用,如果沒有被占用則將值放入其中。當HashTable中的可用空間越來越小時,則獲取得到可用空間的難度越來越大,消耗的時間就越多。
5..當前HashTable中的被占用空間達到一個百分比的時候就將該空間自動擴容,在.net中這個百分比是72%,也叫.net中HashTable的填充因數為0.72。例如有一個HashTable的空間大小是100,當它需要添加第73個值的時候將會擴容此HashTable.
6.這個自動擴容的大小是多少呢?答案是當前空間大小的兩倍最接近的素數,例如當前HashTable所占空間為素數71,如果擴容,則擴容大小為素數131.
二:Dictionary
1.Dictionary是一種變種的HashTable,它採用一種分離鏈接散列表的數據結構來解決哈希衝突的問題。
2.分離鏈接散列表是當散列到同一個地址的值存為一個鏈表中。
3.這個變種HashTable的填充因數是1
eg:本文將以代碼的形式探索HashTable和Dictionary的插入和三種讀取方式的效率(for/foreach/GetEnumerator)
public class HashTableTest { static Hashtable _Hashtable; static Dictionary<string, object> _Dictionary; static void Main() { Compare(10); Compare(10000); Compare(5000000); Console.ReadLine(); } public static void Compare(int dataCount) { Console.WriteLine("-------------------------------------------------\n"); _Hashtable = new Hashtable(); _Dictionary = new Dictionary<string, object>(); Stopwatch stopWatch = new Stopwatch(); //HashTable插入dataCount條數據需要時間 stopWatch.Start(); for (int i = 0; i < dataCount; i++) { _Hashtable.Add("Str" + i.ToString(), "Value"); } stopWatch.Stop(); Console.WriteLine(" HashTable插入" + dataCount + "條數據需要時間:" + stopWatch.Elapsed); //Dictionary插入dataCount條數據需要時間 stopWatch.Reset(); stopWatch.Start(); for (int i = 0; i < dataCount; i++) { _Dictionary.Add("Str" + i.ToString(), "Value"); } stopWatch.Stop(); Console.WriteLine(" Dictionary插入" + dataCount + "條數據需要時間:" + stopWatch.Elapsed); //Dictionary插入dataCount條數據需要時間 stopWatch.Reset(); int si = 0; stopWatch.Start(); for(int i=0;i<_Hashtable.Count;i++) { si++; } stopWatch.Stop(); Console.WriteLine(" HashTable遍歷時間:" + stopWatch.Elapsed + " ,遍歷採用for方式"); //Dictionary插入dataCount條數據需要時間 stopWatch.Reset(); si = 0; stopWatch.Start(); foreach (var s in _Hashtable) { si++; } stopWatch.Stop(); Console.WriteLine(" HashTable遍歷時間:" + stopWatch.Elapsed + " ,遍歷採用foreach方式"); //Dictionary插入dataCount條數據需要時間 stopWatch.Reset(); si = 0; stopWatch.Start(); IDictionaryEnumerator _hashEnum = _Hashtable.GetEnumerator(); while (_hashEnum.MoveNext()) { si++; } stopWatch.Stop(); Console.WriteLine(" HashTable遍歷時間:" + stopWatch.Elapsed + " ,遍歷採用HashTable.GetEnumerator()方式"); //Dictionary插入dataCount條數據需要時間 stopWatch.Reset(); si = 0; stopWatch.Start(); for(int i=0;i<_Dictionary.Count;i++) { si++; } stopWatch.Stop(); Console.WriteLine(" Dictionary遍歷時間:" + stopWatch.Elapsed + " ,遍歷採用for方式"); //Dictionary插入dataCount條數據需要時間 stopWatch.Reset(); si = 0; stopWatch.Start(); foreach (var s in _Dictionary) { si++; } stopWatch.Stop(); Console.WriteLine(" Dictionary遍歷時間:" + stopWatch.Elapsed + " ,遍歷採用foreach方式"); //Dictionary插入dataCount條數據需要時間 stopWatch.Reset(); si = 0; stopWatch.Start(); _hashEnum = _Dictionary.GetEnumerator(); while (_hashEnum.MoveNext()) { si++; } stopWatch.Stop(); Console.WriteLine(" Dictionary遍歷時間:" + stopWatch.Elapsed + " ,遍歷採用Dictionary.GetEnumerator()方式"); Console.WriteLine("\n-------------------------------------------------"); } }
四:從上面的結果可以看出
1.HashTable大數據量插入數據時需要花費比Dictionary大的多的時間。
2.for方式遍歷HashTable和Dictionary速度最快。
3.在foreach方式遍歷時Dictionary遍歷速度更快。
五:在單線程的時候使用Dictionary更好一些,多線程的時候使用HashTable更好。
因為HashTable可以通過Hashtable tab = Hashtable.Synchronized(new Hashtable());獲得線程安全的對象。
eg: hashtable
public static Hashtable List() { Hashtable h = new Hashtable(); h.Add(1,"asdasdsad"); h.Add("dasda","dsadsa"); return h; } Hashtable list=List(); foreach(Object item in list.Keys){ Console.WriteLine(item); Console.WriteLine(list[item]); }
三:遍歷方式:
Dictionary的幾種遍歷方式:
Dictionary<string, int> list = new Dictionary<string, int>(); list.Add("d", 1); //一:通過key值遍歷: foreach (string key in list.Keys) { Console.WriteLine(key + list[key]); } //二:通過value值遍歷: foreach (int val in list.Values){ Console.WriteLine(val); } //三:通過key和value遍歷: foreach (KeyValuePair<string, int> kv in list){ Console.WriteLine(kv.Key + kv.Value); } //四:3.0以上版本 foreach (var item in list){ Console.WriteLine(item.Key + item.Value); }
HashTable的遍歷方式:
static void Main(string[] args) 2 { 3 Person person1 = new Person(); 4 person1.Age = 34; 5 person1.Name = "Jacky"; 6 person1.Email = "[email protected]"; 7 8 Person person2 = new Person(); 9 person2.Age = 23; 10 person2.Name = "Ajay"; 11 person2.Email = "[email protected]"; 12 13 Person person3 = new Person(); 14 person3.Age = 12; 15 person3.Name = "Bill"; 16 person3.Email = "[email protected]"; 17 18 Person person4 = new Person(); 19 person4.Age = 23; 20 person4.Name = "Gace"; 21 person4.Email = "[email protected]"; 22 23 Person person5 = new Person(); 24 person5.Age = 45; 25 person5.Name = "Jim"; 26 person5.Email = "[email protected]"; 27 28 Hashtable ht = new Hashtable(); 29 ht.Add("1", person1); 30 ht.Add("2", person2); 31 ht.Add("3", person3); 32 ht.Add("4", person4); 33 ht.Add("5", person5); 34 Console.WriteLine("請輸入你的查詢的用戶名:"); 35 string strName = Console.ReadLine(); 36 //第一種方法 key值 37 foreach (string item in ht.Keys) 38 { 39 Person p = (Person)ht[item]; 40 if (strName == p.Name) 41 { 42 Console.WriteLine("查詢後的結果是:" + p.Name + "\t" + p.Email + "\t" + p.Age); 43 } 44 } 45 46 47 48 //第二種方法 value值 49 foreach (Person item in ht.Values) 50 { 51 if (item.Name == strName) 52 { 53 Console.WriteLine("查詢後的結果是:" + item.Name + "\t" + item.Email + "\t" + item.Age); 54 } 55 56 } 57 //第三種方法 key和value值 58 foreach (DictionaryEntry item in ht) 59 { 60 if (strName == ((Person)item.Value).Name) 61 { 62 Console.WriteLine("查詢後的結果是:" + ((Person)item.Value).Name + "\t" + ((Person)item.Value).Email + "\t" + ((Person)item.Value).Age); 63 } 64 } 65 66 //第四種方法 67 IDictionaryEnumerator id = ht.GetEnumerator(); 68 while (id.MoveNext()) 69 { 70 Person p = (Person)ht[id.Key]; 71 if (p.Name == strName) 72 { 73 Console.WriteLine("查詢後的結果是:" + p.Name + "\t" + p.Email + "\t" + p.Age); 74 } 75 } 76 77 }
第四:Queue集合和Stack
Queue:它是一個先進先出的集合(它存儲於隊列中),先進先出的意思也就是最先放進集合的數據,拿數據的時候從最初放進去的數據開始拿。
Stack:它是一個後進先出的集合(它存儲於棧中),後進先出的意思顧名思義,也就是說取數據只能從最後放進去的那個數據開始取。
以下代碼實例了分別使用Stack和Queue列印數字0~9。
//寫入數據到Queue中 2. Queue q = new Queue(); 3. for (int i = 0; i < 10; i++) 4. { 5. q.Enqueue(i); 6. } 7. 8. 9. //迴圈輸出Queue所有數據 10. Console.WriteLine("開始輸出Queue數據"); 11. while (q.Count > 0) 12. { 13. Console.WriteLine(q.Dequeue()); 14. } 15. 16. //-------------------------------------分割線------------------------------------// 17. 18. //寫入數據到Stack中 19. Stack s = new Stack(); 20. for (int i = 0; i < 10; i++) 21. { 22. s.Push(i); 23. } 24. 25. //迴圈輸出所有Stack數據 26. Console.WriteLine("開始輸出Stack數據"); 27. while (s.Count > 0) 28. { 29. Console.WriteLine(s.Pop()); 30. }
輸出結果:
基於以下代碼對Queue 與 Stack進行了性能測試,他們的性能都比數組要高大約2~倍。
Stopwatch sw_queue = new Stopwatch(); 2. sw_queue.Start(); 3. 4. //寫入數據到Queue中 5. Queue q = new Queue(); 6. for (int i = 0; i < 1000000; i++) 7. { 8. q.Enqueue(i); 9. } 10. 11. //迴圈輸出Queue所有數據 12. while (q.Count > 0) 13. { 14. q.Dequeue(); 15. } 16. 17. sw_queue.Stop(); // 停止監視 18. Console.WriteLine("Queue 100萬數據寫入讀取消耗時間:{0}毫秒", sw_queue.Elapsed.TotalMilliseconds.ToString()); 19. 20. //---------------------------------分割線--------------------------------// 21. 22. Stopwatch sw_stack = new Stopwatch(); 23. sw_stack.Start(); 24. 25. 26. //寫入數據到Stack中 27. Stack s = new Stack(); 28. for (int i = 0; i < 1000000; i++) 29. { 30. s.Push(i); 31. } 32. 33. //迴圈輸出所有Stack數據 34. while (s.Count > 0) 35. { 36. s.Pop(); 37. } 38. 39. sw_stack.Stop(); // 停止監視 40. Console.WriteLine("Stack 100萬數據寫入讀取消耗時間:{0}毫秒", sw_stack.Elapsed.TotalMilliseconds.ToString()); 41. 42. 43. Console.R
eadKey();
測試結果:
Queue 的主要成員:
屬性
Count //元素數
方法
Clear() //清空
Contains() //是否包含
Dequeue() //出列
Enqueue() //入列
Peek() //獲取將要出列的
Stack 的主要成員:
屬性 Count //
方法
Clear() //
Contains() //
Peek() //獲取將要出棧的
Pop() //出棧
Push() //壓棧
第五:SortedList
1、SortedList定義
System.Collections.SortedList類表示鍵/值對的集合,這些鍵值對按鍵排序並可按照鍵和索引訪問。SortedList 在內部維護兩個數組以存儲列表中的元素;即,一個數組用於鍵,另一個數組用於相關聯的值。每個元素都是一個可作為 DictionaryEntry 對象進行訪問的鍵/值對。鍵不能為null,但值可以。
2.優點
1、SortedList 允許通過相關聯鍵或通過索引對值進行訪問,可提供更大的靈活性。
2、可根據需要自動增大容量。
3.註意點:
1、SortedList 的容量是 SortedList 可以保存的元素數。SortedList 的預設初始容量為 0。隨著元素添加到 SortedList 中,在需要時可以通過重新分配自動增加容量。可通過調用 TrimToSize方法 或通過顯式設置 Capacity 屬性減少容量。
2、SortedList 中不允許重覆鍵。
3、SortedList的索引順序基於排序順序。當添加元素時,元素將按正確的排序順序插入 SortedList,同時索引會相應地進行調整。當移除元素時,索引也會相應地進行調整。因此,當在 SortedList 中添加或移除元素時,特定鍵/值對的索引可能會更改。
4.當不向集合中添加新元素,則調用TrimToSize方法可用於最小化集合的記憶體開銷。
5、通過設置 SortedList 中不存在的鍵值(例如,myCollection["myNonexistentKey"] = myValue),還可以使用 Item 屬性添加新元素。但是,如果指定的鍵已經存在於 SortedList 中,則設置 Item 屬性將改寫舊值。相比之下,Add 方法不修改現有元素。
鍵不能為 空引用(在 Visual Basic 中為 Nothing),但值可以。若要區分由於未找到指定鍵而返回的 空引用(在 Visual Basic 中為 Nothing) 和由於指定鍵的值為 空引用(在 Visual Basic 中為 Nothing) 而返回的 空引用(在 Visual Basic 中為 Nothing),請使用 Contains 方法或 ContainsKey 方法確定列表中是否存在該鍵。
4. SortedList的構造器
5、SortedList的屬性
6.SortedList的方法
泛型集合SortedList<TKey,TValue>:
如果需要排好序的表,可以使用SortedList<TKey,TValue>。這個類按照鍵給元素排序。
下麵的例子創建一個有序表,其中鍵和值都是string類型。預設的構造函數創建了一個空表,再用Add()方法添加兩本書。使用重載的構造函數,可以定義有序表的容量,傳送執行了IComparer<TKey>介面的對象,用於給有序表中得元素排序。
Add()方法的第一個參數是鍵(書名),第二個參數是值(ISBN號)。除了使用Add()方法之外,還可以使用索引器將元素添加到有序表中。索引器需要把鍵作為索引參數。如果鍵已存在,那麼Add()方法就拋出一個ArgumentException類型的異常。如果索引器使用相同的鍵,就用新值替代舊值。
static void Main(string[] args) 06. { 07. // 創建一個SortedList對象 08. SortedList mySortedList = new SortedList(); 09. mySortedList.Add("First", "Hello"); 10. mySortedList.Add("Second", "World"); 11. mySortedList.Add("Third", "!"); 12. mySortedList.Add("Four", "{1}quot;); 13. 14. //列舉SortedList的屬性、鍵、值 15. Console.WriteLine("MySortedList"); 16. Console.WriteLine(" Count: {0}", mySortedList.Count); 17. Console.WriteLine(" Capacity: {0}", mySortedList.Capacity); 18. Console.WriteLine(" Keys and Values:"); 19. PrintIndexAndKeysAndValues(mySortedList); 20. 21. #region SortedList獲得鍵、值列表 22. SortedList mySortedList1 = new SortedList(); 23. mySortedList1.Add(1.3, "fox"); 24. mySortedList1.Add(1.4, "jumped"); 25. mySortedList1.Add(1.5, "over"); 26. mySortedList1.Add(1.2, "brown"); 27. mySortedList1.Add(1.1, "quick"); 28. mySortedList1.Add(1.0, "The"); 29. mySortedList1.Add(1.6, "the"); 30. mySortedList1.Add(1.8, "dog");