1. 程式人生 > >(轉) C#解惑:HashSet<T>類

(轉) C#解惑:HashSet<T>類

detail lan http 求交集 方式 tail collect 內部 方法

HashSet<T>是一個相對“冷門”的類型,平時在項目中用得不多,但是在特定的業務中可以大用。

先來了解下HashSet<T>類,主要被設計用來存儲集合,做高性能集運算,例如兩個集合求交集、並集、差集等。從名稱可以看出,它是基於Hash的,可以簡單理解為沒有Value的Dictionary。

HashSet<T>不能用索引訪問,不能存儲重復數據,元素T必須正確實現了EqualsGetHashCode

HashSet<T>的一些特性如下:

  1. HashSet<T>中的值不能重復且沒有順序。
  2. HashSet<T>的容量會按需自動添加。

HashSet<T>的優勢和與List<T>的比較

HashSet<T>最大的優勢是檢索的性能,簡單的說它的Contains方法的性能在大數據量時比List<T>好得多。曾經做過一個測試,將800W條int類型放在List<int>集合中,使用Contains判斷是否存在,速度巨慢,而放在HashSet<int>性能得到大幅提升。

在內部算法實現上,HashSet<T>的Contains方法復雜度是O(1),List<T>的Contains方法復雜度是O(n),後者數據量越大速度越慢,而HashSet<T>

不受數據量的影響。

所以在集合的目的是為了檢索的情況下,我們應該使用HashSet<T>代替List<T>。比如一個存儲關鍵字的集合,運行的時候通過其Contains方法檢查輸入字符串是否關鍵字。

在3.5之前,想用哈希表來提高集合的查詢效率,只有Hashtable和Dictionary兩種選擇,而這兩種都是鍵-值方式的存儲。但有些時候,我們只需要其中一個值,例如一個Email集合,如果用泛型哈希表來存儲,往往要在Key和Value各保存一次,不可避免的要造成內存浪費。而HashSet只保存一個值,更加適合處理這種情況。

此外,HashSet的Add方法返回bool值,在添加數據時,如果發現集合中已經存在,則忽略這次操作,並返回false值。而Hashtable和Dictionary碰到重復添加的情況會直接拋出錯誤。

從使用上來看,HashSet和線性集合List更相似一些,但前者的查詢效率有著極大的優勢。假如,用戶註冊時輸入郵箱要檢查唯一性,而當前已註冊的郵箱數量達到10萬條,如果使用List進行查詢,需要遍歷一次列表,時間復雜度為O(n),而使用HashSet則不需要遍歷,通過哈希算法直接得到列表中是否已存在,時間復雜度為O(1),這是哈希表的查詢優勢。

和List的區別

HashSet是Set集合,它只實現了ICollection接口,在單獨元素訪問上,有很大的限制:

跟List相比,不能使用下標來訪問元素,如:list[1] 。

跟Dictionary相比,不能通過鍵值來訪問元素,例如:dic[key],因為HashSet每條數據只保存一項,並不采用Key-Value的方式,換句話說,HashSet中的Key就是Value,假如已經知道了Key,也沒必要再查詢去獲取Value,需要做的只是檢查值是否已存在。

所以剩下的僅僅是開頭提到的集合操作,這是它的缺點,也是特點。

集合運算

IntersectWith (IEnumerable other) (交集)

  1. public void IntersectWithTest()
  2. {
  3. HashSet<int> set1 = new HashSet<int>() { 1, 2, 3 };
  4. HashSet<int> set2 = new HashSet<int>() { 2, 3, 4 };
  5. set1.IntersectWith(set2);
  6. foreach (var item in set1)
  7. {
  8. Console.WriteLine(item);
  9. }
  10. //輸出:2,3
  11. }

UnionWith (IEnumerable other) (並集)

public void UnionWithTest()
{
HashSet set1 = new HashSet() { 1, 2, 3 };
HashSet set2 = new HashSet() { 2, 3, 4 };

  1. set1.UnionWith(set2);
  2. foreach (var item in set1)
  3. {
  4. Console.WriteLine(item);
  5. }
  6. //輸出:1,2,3,4
  7. }

ExceptWith (IEnumerable other) (排除)

public void ExceptWithTest()
{
HashSet set1 = new HashSet() { 1, 2, 3 };
HashSet set2 = new HashSet() { 2, 3, 4 };

  1. set1.ExceptWith(set2);
  2. foreach (var item in set1)
  3. {
  4. Console.WriteLine(item);
  5. }
  6. //輸出:1
  7. }
原貼: https://blog.csdn.net/X_X_OO/article/details/52529548

(轉) C#解惑:HashSet<T>類