說,我有一個類索引從它創建的所有對象從0,...,n-1(使用創建對象的靜態計數器)。由於這些對象用於HashSets和Dictionaries,我們需要一個Hash函數。索引對象的散列函數
是否有任何理由不使用此索引作爲哈希值?
說,我有一個類索引從它創建的所有對象從0,...,n-1(使用創建對象的靜態計數器)。由於這些對象用於HashSets和Dictionaries,我們需要一個Hash函數。索引對象的散列函數
是否有任何理由不使用此索引作爲哈希值?
這裏是actual code對一個HashSet包含
private int[] m_buckets;
private Slot[] m_slots;
public bool Contains(T item) {
if (m_buckets != null) {
int hashCode = InternalGetHashCode(item);
// see note at "HashSet" level describing why "- 1" appears in for loop
for (int i = m_buckets[hashCode % m_buckets.Length] - 1; i >= 0; i = m_slots[i].next) {
if (m_slots[i].hashCode == hashCode && m_comparer.Equals(m_slots[i].value, item)) {
return true;
}
}
}
// either m_buckets is null or wasn't found
return false;
}
private int InternalGetHashCode(T item) {
if (item == null) {
return 0;
}
return m_comparer.GetHashCode(item) & Lower31BitMask;
}
internal struct Slot {
internal int hashCode; // Lower 31 bits of hash code, -1 if unused
internal T value;
internal int next; // Index of next entry, -1 if last
}
要注意的關鍵事情是它調用GetHashCode()
那麼它hashCode % m_buckets.Length
的結果找出哪些奇異鏈表根存儲在m_slots
應它遍歷。
最好的算法會給你在整個hashCode % m_buckets.Length
之間均勻分佈的值,所以所有的鏈表都是相同的長度。從0開始算起來完美無缺,所以是的,如果你可以得到一個固定索引的對象是唯一的,並且只是計算出來就是一個完美的哈希碼。
不使用索引作爲散列函數的一個原因是因爲你想在不同實例中重複使用。
假設您在實體系統中使用Dictionaty
,並且您的密鑰是任何給定Component的實體和組件類型的組合。查找組件時,您希望能夠從實體,組件類型創建一個新密鑰,並使其等同於具有相同實體和組件類型的密鑰。通過這種方式,靜態遞增索引不是要走的路,因爲它會導致表示具有不同HashCode的相同值的對象,導致它在Dictionary中不起作用。
另一個原因是,您可能擁有數量過多的對象而不是運行在具有延長生命週期的程序中的類型 - 比方說數據庫驅動程序上的事務管理器。在這種情況下,您可能實際上用完整數值(如果允許使用否定值,則使用約42億個值)或使用uint
。在這種情況下,散列碼不足以支持唯一性 - 這是散列碼的正常行爲,但是對於過度優化而言,這是一個非常可能的問題。
你當然可以使用它,但如果你這樣做,這意味着每個單獨的對象實例被這些基於散列的結構視爲不同的對象。如果你希望不同的對象實例能夠被認爲是「相等的」,那麼這種方法將不起作用。
如果這實際上是你的目標,那麼根本沒有理由重寫默認的相等/散列碼語義。默認實現將比較對象引用,導致每個對象與其他對象「不同」。所以省下你的努力,只是不要打擾什麼。
速度怎麼樣?使用索引比在64位引用上使用標準哈希函數更快一些? – 2015-01-09 20:24:08
@JFMeier我非常懷疑你甚至能夠衡量差異。幾乎沒有機會花費時間評估。如果你的程序花費太長時間,有更好的地方花費你的時間。 – Servy 2015-01-09 20:25:14
謝謝。誰低估了你 - 不是我。 – 2015-01-09 20:26:41
這是一個非常模糊的問題,但只要索引永遠不會改變(比如說,如果其中一些被刪除),它應該是一個合理的散列。 – ahruss 2015-01-09 20:11:31
在這種情況下,索引將是一個完美的散列。 – leppie 2015-01-09 20:12:57
詢問的原因是人們經常聽說散列函數應該「散佈在整數之上」,但是如果你生成了一千個對象,給它們散列值從0到999會有什麼傷害嗎? – 2015-01-09 20:13:45