我正在尝试实现自己的哈希函数,我使用java将每个字符串的ASCII编号相加。我通过查找哈希表大小和总和来找到哈希码。大小%之和。我想知道在搜索字符串时是否有办法使用相同的进程但减少了冲突?
提前致谢。
答案 0 :(得分:6)
Java String.hashcode()在一个非常好的哈希函数和尽可能高效的哈希函数之间进行权衡。简单地在字符串中添加字符值不是可靠的散列函数。
例如,考虑两个字符串dog
和god
。由于它们都包含'd','g'和'o',因此任何仅涉及添加的方法都不会产生不同的哈希码。
Joshua Bloch,他实现了Java的一部分,讨论了他的书Effective Java中的String.hashCode()方法,并讨论了1.3之前的Java版本中的String.hashCode ()函数用于仅考虑给定String中的16个字符。这比当前的实施速度稍微快一点,但在某些情况下导致的表现令人震惊。
通常,如果您的特定数据集定义得非常明确并且可以利用其中的某些唯一性,那么您可能会创建更好的散列函数。对于通用字符串,祝你好运。
答案 1 :(得分:6)
我会查看String和HashMap的代码,因为它们具有较低的冲突率,并且不使用%
并处理负数。
来自String的来源
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
来自HashMap的来源
/**
* Retrieve object hash code and applies a supplemental hash function to the
* result hash, which defends against poor quality hash functions. This is
* critical because HashMap uses power-of-two length hash tables, that
* otherwise encounter collisions for hashCodes that do not differ
* in lower bits. Note: Null keys always map to hash 0, thus index 0.
*/
final int hash(Object k) {
int h = 0;
if (useAltHashing) {
if (k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h = hashSeed;
}
h ^= k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
由于HashMap总是2的幂,你可以使用
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
和
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
使用&
比%
快得多,只有长度为正才会返回正数。