2015-01-09 54 views
2

说,我有一个类索引从它创建的所有对象从0,...,n-1(使用创建对象的静态计数器)。由于这些对象用于HashSets和Dictionaries,我们需要一个Hash函数。索引对象的散列函数

是否有任何理由不使用此索引作为哈希值?

+0

这是一个非常模糊的问题,但只要索引永远不会改变(比如说,如果其中一些被删除),它应该是一个合理的散列。 – ahruss 2015-01-09 20:11:31

+1

在这种情况下,索引将是一个完美的散列。 – leppie 2015-01-09 20:12:57

+0

询问的原因是人们经常听说散列函数应该“散布在整数之上”,但是如果你生成了一千个对象,给它们散列值从0到999会有什么伤害吗? – 2015-01-09 20:13:45

回答

1

这里是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开始算起来完美无缺,所以是的,如果你可以得到一个固定索引的对象是唯一的,并且只是计算出来就是一个完美的哈希码。

0

不使用索引作为散列函数的一个原因是因为你想在不同实例中重复使用

假设您在实体系统中使用Dictionaty,并且您的密钥是任何给定Component的实体和组件类型的组合。查找组件时,您希望能够从实体,组件类型创建一个新密钥,并使其等同于具有相同实体和组件类型的密钥。通过这种方式,静态递增索引不是要走的路,因为它会导致表示具有不同HashCode的相同值的对象,导致它在Dictionary中不起作用。

另一个原因是,您可能拥有数量过多的对象而不是运行在具有延长生命周期的程序中的类型 - 比方说数据库驱动程序上的事务管理器。在这种情况下,您可能实际上用完整数值(如果允许使用否定值,则使用约42亿个值)或使用uint。在这种情况下,散列码不足以支持唯一性 - 这是散列码的正常行为,但是对于过度优化而言,这是一个非常可能的问题。

+0

你的int max值是它们应该是的2倍。 – Servy 2015-01-09 20:26:54

+0

是的,不正确地运行 - 缓刑 – David 2015-01-09 20:28:30

3

你当然可以使用它,但如果你这样做,这意味着每个单独的对象实例被这些基于散列的结构视为不同的对象。如果你希望不同的对象实例能够被认为是“相等的”,那么这种方法将不起作用。

如果这实际上是你的目标,那么根本没有理由重写默认的相等/散列码语义。默认实现将比较对象引用,导致每个对象与其他对象“不同”。所以省下你的努力,只是不要打扰什么

+0

速度怎么样?使用索引比在64位引用上使用标准哈希函数更快一些? – 2015-01-09 20:24:08

+0

@JFMeier我非常怀疑你甚至能够衡量差异。几乎没有机会花费时间评估。如果你的程序花费太长时间,有更好的地方花费你的时间。 – Servy 2015-01-09 20:25:14

+0

谢谢。谁低估了你 - 不是我。 – 2015-01-09 20:26:41