簡體   English   中英

如果我從未使用過HashSet,我還應該實現GetHashCode嗎?

[英]If I never ever use HashSet, should I still implement GetHashCode?

我永遠不需要將對象存儲在哈希表中。 原因有兩個:

  • 提出一個好的哈希函數很難並且容易出錯。
  • AVL樹幾乎總是足夠快,它只需要一個嚴格的順序謂詞,這更容易實現。

另一方面,Equals()操作是一種非常常用的功能。

因此我想知道在實現Equals函數(我經常需要)時是否有必要實現GetHashCode(我從不需要)?

我的建議 - 如果你不想使用它,覆蓋它並throw new NotImplementedException(); 這樣你就會看到你需要它的地方。

如果您認為實現嚴格的順序謂詞比散列函數更容易實現,我認為您錯了 - 它需要處理大量邊緣情況(空值,類層次結構)。 哈希函數並不那么難 ,真的。

AVL樹比哈希表慢得多。 如果您只處理幾件物品,那么這不會是一個大問題。 Hashtables具有O(1)插入,刪除和搜索,但AVL樹具有O(log(n))操作。

我會繼續並覆蓋GetHashCodeEquals有兩個原因。

  • 通過使用簡單的XOR實現來獲得合適的分布並不困難。 1
  • 如果您的類是公共API的一部分,那么其他人可能希望將它們存儲在哈希表中。

另外,我不得不質疑BST的選擇。 AVL樹有點不合時宜。 還有其他更現代的BST更容易實現和工作(有時更好)。 如果您確實需要維護排序的數據結構,那么請考慮這些替代方案。


1 XOR策略存在一個微妙的關聯性問題,在某些情況下可能會導致沖突,因為a^b = b^a Effective Java提供了一個解決方案,它實現了類似於邪教的識別,並且實現起來相當簡單。

如果你使用DictionarySortedList ,並重寫Equals ,你需要有一個哈希函數,否則它們會破壞。 Equals也在BCL中的所有地方使用,如果其他人使用你的對象,他們會期望GetHashCode表現得合理。

請注意,散列函數不必那么復雜。 基本版本是獲取您用於相等的任何成員變量的哈希值,將每個成員變量與一個單獨的互質數相乘,並將它們一起進行異或。

您不需要實現它。 如果你編寫自己的Equals()方法,我建議使用一些不破壞HashSet的GetHashCode實現。 例如,您可以返回靜態值(通常為42)。 HashSet性能會急劇下降,但至少它仍然可以工作 - 你永遠不會知道將來誰會使用/編輯/維護你的代碼。 (編輯:如果在散列結構中使用這樣的類以便及早發現性能問題,則可能需要記錄警告)

編輯:不要只使用XOR來組合屬性的哈希碼

其他人已經說過,您可以簡單地組合所有屬性的哈希碼。 而不是只使用XOR我會鼓勵倍增結果。 如果兩個值相等(例如0xA ^ 0xA == 0x0 ),則XOR可能導致0值。 使用0xA * 0xA0xA * 31 + 0xA0xA ^ (0xA * 31)可以輕松改善這一點。

盡管如此,我的答案的意圖是任何散列函數都優於與equals不一致的函數 - 即使它只返回一個靜態值。 只需選擇用於相等性的任何屬性子集(從none到all)並將結果放在一起。 在選擇哈希碼的屬性時,更喜歡那些組合非常獨特的小子集(例如,名字,姓氏,生日 - 不需要添加整個地址)

提供足夠的哈希函數並不困難。 大多數情況下,所有字段的GetHashCode()結果的簡單XOR就足夠了。

如果覆蓋equals,則應覆蓋MSDN中的GetHashCode():“建議任何覆蓋Equals的類也覆蓋System.Object.GetHashCode。” http://msdn.microsoft.com/en-us/library/ms173147.aspx

這兩個函數應該匹配,如果兩個對象相等,它們應該具有相同的散列值。 這並不意味着如果兩個對象具有相同的散列,則它們應該相等。 您不需要過於復雜的哈希算法,但它應該嘗試在整數空間中很好地分布。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM