我有一个类,内部只是一个整数数组。一旦构造,该数组永远不会改变。我想预先计算出一个好的哈希码,以便该类可以作为Dictionary中的键被非常高效地使用。数组长度少于30个项,通常情况下整数值在-1000到1000之间。
我有一个类,内部只是一个整数数组。一旦构造,该数组永远不会改变。我想预先计算出一个好的哈希码,以便该类可以作为Dictionary中的键被非常高效地使用。数组长度少于30个项,通常情况下整数值在-1000到1000之间。
虽然不是非常聪明,但足以满足大多数实际需求:
编辑:由于Henk Holterman的评论而进行更改,感谢他的建议。
int hc = array.Length;
foreach (int val in array)
{
hc = unchecked(hc * 314159 + val);
}
如果您需要更先进的东西,请点击这里。
hc=unchecked(hc*SHIFTVAL+array[i]);
修改为与编译器设置无关的代码。 - H HEquals
方法发挥作用的地方。据我所记,字典使用 Equals
方法来区分具有相同哈希值的对象(这就是为什么 Equals
方法不应该依赖于哈希本身)。 - Alisson Reinaldo Silva对于一组通常在-1000和1000之间的值,我可能会使用以下代码:
static int GetHashCode(int[] values)
{
int result = 0;
int shift = 0;
for (int i = 0; i < values.Length; i++)
{
shift = (shift + 11) % 21;
result ^= (values[i]+1024) << shift;
}
return result;
}
你也可以使用 Linq 方法:
var array = new int[10];
var hashCode = array.Aggregate(0, (a, v) =>
HashCode.Combine(a, v.GetHashCode()));
您可以使用CRC32校验和。以下是代码:
[CLSCompliant(false)]
public class Crc32 {
uint[] table = new uint[256];
uint[] Table { get { return table; } }
public Crc32() {
MakeCrcTable();
}
void MakeCrcTable() {
for (uint n = 0; n < 256; n++) {
uint value = n;
for (int i = 0; i < 8; i++) {
if ((value & 1) != 0)
value = 0xedb88320 ^ (value >> 1);
else
value = value >> 1;
}
Table[n] = value;
}
}
public uint UpdateCrc(uint crc, byte[] buffer, int length) {
uint result = crc;
for (int n = 0; n < length; n++) {
result = Table[(result ^ buffer[n]) & 0xff] ^ (result >> 8);
}
return result;
}
public uint Calculate(Stream stream) {
long pos = stream.Position;
const int size = 0x32000;
byte[] buf = new byte[size];
int bytes = 0;
uint result = 0xffffffff;
do {
bytes = stream.Read(buf, 0, size);
result = UpdateCrc(result, buf, bytes);
}
while (bytes == size);
stream.Position = pos;
return ~result;
}
}
我正在这里使用它
var arrayHash = string.Join(string.Empty, array).GetHashCode();
任何CRC(甚至XOR)都可以。
internal class DictionaryEntry<TKey, TValue>
{
public Dictionary<TKey, DictionaryEntry<TKey, TValue>> Children { get; private set; }
public TValue Value { get; private set; }
public bool HasValue { get; private set; }
public void SetValue(TValue value)
{
Value = value;
HasValue = true;
}
public DictionaryEntry()
{
Children = new Dictionary<TKey, DictionaryEntry<TKey, TValue>>();
}
}
internal class KeyStackDictionary<TKey, TValue>
{
// Helper dictionary to work with a stack of keys
// Usage:
// var dict = new KeyStackDictionary<int, string>();
// int[] keyStack = new int[] {23, 43, 54};
// dict.SetValue(keyStack, "foo");
// string value;
// if (dict.GetValue(keyStack, out value))
// {
// }
private DictionaryEntry<TKey, TValue> _dict;
public KeyStackDictionary()
{
_dict = new DictionaryEntry<TKey, TValue>();
}
public void SetValue(TKey[] keyStack, TValue value)
{
DictionaryEntry<TKey, TValue> dict = _dict;
for (int i = 0; i < keyStack.Length; i++)
{
TKey key = keyStack[i];
if (dict.Children.ContainsKey(key))
{
dict = dict.Children[key];
}
else
{
var child = new DictionaryEntry<TKey, TValue>();
dict.Children.Add(key, child);
dict = child;
}
if (i == keyStack.Length - 1)
{
dict.SetValue(value);
}
}
}
// returns false if the value is not found using the key stack
public bool GetValue(TKey[] keyStack, out TValue value)
{
DictionaryEntry<TKey, TValue> dict = _dict;
for (int i = 0; i < keyStack.Length; i++)
{
TKey key = keyStack[i];
if (dict.Children.ContainsKey(key))
{
dict = dict.Children[key];
}
else
{
break;
}
if (i == keyStack.Length - 1 && dict.HasValue)
{
value = dict.Value;
return true;
}
}
value = default(TValue);
return false;
}
}
HashCode.Combine(array)
适用于.NET Core 2.1 / .NET Standard 2.1 / .NET 5及更高版本。
HashCode.Add()
的正确解决方案在 https://dev59.com/aFIH5IYBdhLWcg3wfu1c 上给出。 - Todd West