C# 用雜湊表搜尋對象

來源:互聯網
上載者:User

 

C# 用雜湊表搜尋對象

作者:Bill Wagner

下載原始碼

.NET Framework中的大多數容器都是序列式容器(sequence containers):它們按順序儲存物件。這種類型的容器功能很多——你可以以任何特殊的順序來儲存任意數量的對象。
  然而,這種多功能性是以一定的效能為代價的。在一個序列中尋找一個特殊的對象所需要的時間取決於容器中對象的數量。如果我們沒有對容器中元素進行排序,那麼隨著元素數量的增加,你所需要的尋找時間也就直線增加了:如果容器中元素的數量增加了一倍,那麼你用來尋找一個特殊元素的時間也就增加了一倍。然而,如果我們對容器中的元素進行了排序,那麼尋找時間就是隨著元素數量的對數而增加的了:要使尋找一個元素的時間增加一倍,你必須使集合中的元素數量增加四倍。如果你用一個key來搜尋對象,你可以用比序列式容器更好的方法來儲存你的對象。你可以用雜湊表(hash table)。
  雜湊表根據一個叫做hash的數字關鍵字(key)將Object Storage Service在buckets中。hash value是從對象中的值計算得來的一個數字。每個不同的hash value都會建立一個新的bucket。要尋找一個對象,你只需要計算這個對象的hash value並搜尋相應的bucket就行了。通過快速地找到相應的bucket,就可以減少你需要搜尋的對象數量了。
  例如,設想在一個資料結構中有一些客戶記錄,你想通過信用卡號來搜尋那些記錄。一個簡單的雜湊函數將運用信用卡號的後兩位元字,這會形成100個buckets——從00到99的每個兩位元的數字都會建立一個bucket。(同樣,運用後三位元字會建立1000個buckets。)只需要查詢一個bucket,你就可以找到任何記錄了,而不需要查詢所有的buckets。
  然而,同任何事情一樣,並不是一切都這麼簡單的。如果你用信用卡號建立了一個雜湊函數,而你想通過姓名來尋找客戶,你就需要查詢整個雜湊表,這樣會花很多時間。這是因為雜湊表是用一個不同的欄位作為key的。而且,如果你查詢整個雜湊表,那麼元素就沒有必要按你期望的順序來排列了。元素是根據hash value來排列的,而不是根據keys排列的。
  在本篇文章中,我將詳述我在前面的文章(“為更好的集合建立類”)中的範例,讓你修改一條員工記錄。假設有一個很大的公司,公司裡有上千位員工,你想用最快的方法來找到一條記錄。所有員工的一個雜湊表可以使搜尋在最短的時間完成。
  一個雜湊函數需要有一定的屬性。對於初學者來說,雜湊函數必須是不變的。這就是說相同的key必鬚生成相同的hash value,一旦建立了對象,hash value就不能改變了。如果hash value改變了,你在雜湊表中就再也找不到相應的對象了。
  雜湊函數需要的第二個屬性就是能夠平均分配buckets。如果所有的對象都產生相同的hash value,那麼就需要更多的時間來尋找一個特殊的對象。
  實際上,這兩個原則是很容易遵循的。在.NET Framework中有178個類重載了GetHashCode(),從而更好地發揮它們的作用。所有的.NET FCL(Framework Class Library)中類的實現都確保了hash value的更好的分配,並遵循了唯一性的原則。你應該確定你自己的類和結構是否需要重載GetHashCode()方法。最簡單的(通常也是最好的)方法就是在key中選取一個不變的成員,並運用那個成員所產生的hash value。
  員工資料庫的一個明顯的hash key就是社會保險號(Social Security Number)。它不僅不會改變,而且九位元的這個號碼也可以讓你任意運用以得到你期望的效能。你可以下載範例,看看運用hash keys進行搜尋和運用序列式容器進行搜尋有什麼不同。
要把員工添加到一個雜湊表中,你可以建立一個九位元的號碼並把它作為key:

int hash = 111223333;for (int i = 0; i < 100; i++){   string lastname = "Person" + i.ToString();   e = new Employee ("Employee", lastname, (200-i)*200);   members.Add(hash++, e);}

社會保險號滿足了一個好的hash key的要求:它不會改變,它可以合理地分配、value取決於號碼而不是reference。(你需要運用基於value的hash key而不是基於reference的hash key以避免我以前提到過的問題。)運用這個hash key來尋找對象也很簡單:

 int ssn = Int32.Parse(this.SSN.Text);currentEmp = (Employee)members[ssn];if (currentEmp != null){  LastName.Text = currentEmp.LastName;  FirstName.Text =     currentEmp.FirstName;  Salary.Text =     currentEmp.Salary.ToString ();} else  LastName.Text = "Not Found";

在C#中,你可以用數組文法在雜湊表中尋找對象。該文法強調了恒定時間搜尋的概念:你可以把數組訪問看做是一個快速的操作,而不是一個代價很高的函數調用。
  關於雜湊表最後的一個重點是,同所有的集合一樣,它們也儲存引用(references)。你不需要任何額外的工作來更新雜湊表中的對象。一旦你引用了雜湊表中的一個對象,你可以隨意修改它。記住,同樣的原則不適用於keys。你可以編寫代碼來改變keys,但如果那個代碼修改了hash value,你就會丟失你的集合中的對象。
  雜湊表是很有用的、有效容器。但是,要有效地運用它們,你需要瞭解容器和容器中對象的狀態之間的關係。當你可以用從對象計算得來的不變的value來搜尋對象時,雜湊表就很有用。如果你用不同的順序(通過姓名、社會保險號、或年齡)在對象中搜尋,那麼雜湊表就不那麼有用了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.