C#对象的32位哈希函数
我希望在所有类中重写对象的GetHashCode()方法。此方法返回一个Int32。我所知道的所有加密哈希函数都返回不适合32位整数的值。我想尽量避免碰撞。我应该截断像SHA之类的安全散列,还是使用32位散列?如果使用32位哈希,最好使用哪种32位哈希?哈希值的宽度越短,发生冲突的可能性越大。由于C#对象的32位哈希函数,c#,hash,gethashcode,C#,Hash,Gethashcode,我希望在所有类中重写对象的GetHashCode()方法。此方法返回一个Int32。我所知道的所有加密哈希函数都返回不适合32位整数的值。我想尽量避免碰撞。我应该截断像SHA之类的安全散列,还是使用32位散列?如果使用32位哈希,最好使用哪种32位哈希?哈希值的宽度越短,发生冲突的可能性越大。由于It32/存储了4294967296个不同的值,您需要考虑这些值是否会为您的目的保留足够的值,这将取决于这是为了安全性还是身份检查。 我感兴趣的是,为什么要覆盖GetHashCode(),值是否必须适合
我感兴趣的是,为什么要覆盖
GetHashCode()
,值是否必须适合32位?如果是,原因是什么?您可以通过截断SHA哈希来实现GetHashCode
。但你可能不应该
GetHashCode
的目的是允许将对象插入到。哈希表的目的是优化搜索:平均而言,在哈希表中查找一个键只需要O(1)个时间,而对于树,则需要O(logn),对于未排序的列表,则需要O(n)个时间
您确实希望GetHashCode
方法最小化冲突,以防止哈希表查找退化为O(n)时间。但您也希望它们速度更快,因为哈希表的整个要点是优化。如果您的哈希代码需要很长时间来计算,那么您最好将数据存储在列表中
加密散列速度很慢。它们的设计通常是为了阻止暴力攻击。这使得它们不适合与GetHashCode
一起使用
那么,您应该如何实现GetHashCode
?一种简单、常用的方法就是将Equals
函数中使用的所有成员变量异或在一起
struct Complex
{
double real;
double imag;
public override int GetHashCode()
{
return real.GetHashCode() ^ imag.GetHashCode();
}
// ...
}
另一种简单的方法,适用于类似数组的对象,是
如果类包含大量要散列的数据,则可能需要将散列代码保存在成员变量中,并在构造过程中对其进行预计算,这样GetHashCode()
就可以使用该变量。Eric Lippert创建了一个关于如何正确实现GetHashCode()方法的示例。您需要记住,GetHashCode()的目的是将对象放入哈希表中。出于这个目的使用它意味着您很可能希望在将来某个时候对它进行迭代或排序。如果您使用加密函数来执行此操作,那么迭代或排序过程将运行得非常慢。加密函数旨在保护数据,而不是唯一地标识数据。阅读Eric Lippert的博客文章。它将帮助您解决问题,只需向所有人提供一点信息。不同.NET平台上的GetHashCode()不同。例如,.NET2.0中的“Hello”.GetHashCode()与.NET4.0中的“Hello”.GetHashCode()会产生不同的结果。因此,为什么不能使用.NET即时序列化哈希表或字典
实现您自己的哈希算法可以提供跨平台的一致性。只是想让您知道,您不希望低于Int32。我的建议是坚持使用Int64(long)。这样可以减少冲突,这是散列的目标:)这是我多年前写的一个库。每个散列算法都有它们的加号和减号(速度与最小碰撞)。此特定版本使用字符串作为输入,但您可以根据需要进行修改:
static public class StringHash
{
//---------------------------------------------------------------------
static public Int64 RSHash(String str)
{
const Int32 b = 378551;
Int32 a = 63689;
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = hash * a + str[i];
a = a * b;
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 JSHash(String str)
{
Int64 hash = 1315423911;
for (Int32 i = 0; i < str.Length; i++)
{
hash ^= ((hash << 5) + str[i] + (hash >> 2));
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 ELFHash(String str)
{
Int64 hash = 0;
Int64 x = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = (hash << 4) + str[i];
if ((x = hash & 0xF0000000L) != 0)
{
hash ^= (x >> 24);
}
hash &= ~x;
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 BKDRHash(String str)
{
const Int64 seed = 131; // 31 131 1313 13131 131313 etc..
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = (hash * seed) + str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 SDBMHash(String str)
{
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = str[i] + (hash << 6) + (hash << 16) - hash;
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 DJBHash(String str)
{
Int64 hash = 5381;
for (Int32 i = 0; i < str.Length; i++)
{
hash = ((hash << 5) + hash) + str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 DEKHash(String str)
{
Int64 hash = str.Length;
for (Int32 i = 0; i < str.Length; i++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 BPHash(String str)
{
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = hash << 7 ^ str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 FNVHash(String str)
{
Int64 fnv_prime = 0x811C9DC5;
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash *= fnv_prime;
hash ^= str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 APHash(String str)
{
Int64 hash = 0xAAAAAAAA;
for (Int32 i = 0; i < str.Length; i++)
{
if ((i & 1) == 0)
{
hash ^= ((hash << 7) ^ str[i] * (hash >> 3));
}
else
{
hash ^= (~((hash << 11) + str[i] ^ (hash >> 5)));
}
}
return hash;
}
}
静态公共类StringHash
{
//---------------------------------------------------------------------
静态公共Int64 RSHash(字符串str)
{
常数Int32 b=378551;
INT32A=63689;
Int64散列=0;
对于(Int32 i=0;i2));
}
返回散列;
}
//---------------------------------------------------------------------
静态公共Int64 ELFHash(字符串str)
{
Int64散列=0;
int64x=0;
对于(Int32 i=0;i24);
}
散列&=~x;
}
返回散列;
}
//---------------------------------------------------------------------
静态公共Int64 BKDRHash(字符串str)
{
const Int64 seed=131;//31 1313 131313等。。
Int64散列=0;
对于(Int32 i=0;i hash=str[i]+(哈希为什么要重写GetHashCode
?除非你有很好的理由这样做,并且你了解所有的后果,否则不要这样做。安全性哈希和快速身份检查哈希是两个截然不同的问题。对于身份哈希,你不在乎是否容易派生生成ame散列;您所关心的是它在您使用的典型样本上分布合理,并且计算速度很快。您不需要加密散列,而是需要快速、分布均匀的散列。Cryptogr
static public class StringHash
{
//---------------------------------------------------------------------
static public Int64 RSHash(String str)
{
const Int32 b = 378551;
Int32 a = 63689;
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = hash * a + str[i];
a = a * b;
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 JSHash(String str)
{
Int64 hash = 1315423911;
for (Int32 i = 0; i < str.Length; i++)
{
hash ^= ((hash << 5) + str[i] + (hash >> 2));
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 ELFHash(String str)
{
Int64 hash = 0;
Int64 x = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = (hash << 4) + str[i];
if ((x = hash & 0xF0000000L) != 0)
{
hash ^= (x >> 24);
}
hash &= ~x;
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 BKDRHash(String str)
{
const Int64 seed = 131; // 31 131 1313 13131 131313 etc..
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = (hash * seed) + str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 SDBMHash(String str)
{
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = str[i] + (hash << 6) + (hash << 16) - hash;
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 DJBHash(String str)
{
Int64 hash = 5381;
for (Int32 i = 0; i < str.Length; i++)
{
hash = ((hash << 5) + hash) + str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 DEKHash(String str)
{
Int64 hash = str.Length;
for (Int32 i = 0; i < str.Length; i++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 BPHash(String str)
{
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash = hash << 7 ^ str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 FNVHash(String str)
{
Int64 fnv_prime = 0x811C9DC5;
Int64 hash = 0;
for (Int32 i = 0; i < str.Length; i++)
{
hash *= fnv_prime;
hash ^= str[i];
}
return hash;
}
//---------------------------------------------------------------------
static public Int64 APHash(String str)
{
Int64 hash = 0xAAAAAAAA;
for (Int32 i = 0; i < str.Length; i++)
{
if ((i & 1) == 0)
{
hash ^= ((hash << 7) ^ str[i] * (hash >> 3));
}
else
{
hash ^= (~((hash << 11) + str[i] ^ (hash >> 5)));
}
}
return hash;
}
}