通常说在哈希表中插入和查找字符串是O(1)。但是如何制作字符串的哈希键呢?为什么它不是O(L),字符串的长度? 对我来说很明显,为什么整数是O(1),而不是字符串。
请注意,我理解为什么一般来说,插入哈希表是O(1),但我对将哈希插入表之前的步骤感到困惑;制作哈希值阶段。
在java中的hashTable与C ++中的unordered_map之间如何生成字符串的哈希键之间是否存在任何差异?
答案 0 :(得分:9)
在哈希表中插入等等是O(1),因为它在表中的元素数量中是常量。
" O(1)"在这种情况下,不会声称你可以多快地计算哈希值。如果这种努力以某种方式增长,那就是它的方式。但是,我发现一个体面的(即#34;适合这个应用程序")哈希函数的复杂性不太可能比#34; size"中的线性更差。 (即我们的字符串示例中的长度)被散列的对象。
答案 1 :(得分:3)
通常说在哈希表中插入和查找字符串是O(1)。但是如何制作字符串的哈希键呢?为什么它不是O(L),字符串的长度?对我来说很明显,为什么整数是O(1),而不是字符串。
通常引用的O(1)表示时间不随容器中元素的数量增长。正如你所说,从字符串生成哈希值的时间本身可能不是字符串中的O(1) - 尽管对于某些实现它是:例如Microsoft的C ++ {{1有}:
std::hash<std::string>
size_t _Val = 2166136261U;
size_t _First = 0;
size_t _Last = _Keyval.size();
size_t _Stride = 1 + _Last / 10;
if (_Stride < _Last)
_Last -= _Stride;
for(; _First < _Last; _First += _Stride)
_Val = 16777619U * _Val ^ (size_t)_Keyval[_First];
return (_Val);
是字符串长度的十分之一,因此远离的固定字符数将合并到哈希值中。这样的散列函数是字符串的长度为O(1)。
GCC的C ++标准库采用了不同的方法:至少在v4.7.2中,它通过_Stride
支持类调用_Hash_impl
非成员函数_Hash_bytes
,包含每个字节的Murmur哈希。因此,GCC的static
是字符串长度中的O(N)。
hash<std::string>
和std::unordered_set
的素数桶方面也很明显,MS的实现不会这样做 - 至少在VS2013 / VC12之前;简而言之,MS的方法对于不易发生冲突的键,重量更轻/更快,但是更早,更显着地降级。在java中的hashTable和C ++中的unordered_map之间如何生成字符串的哈希键之间有什么区别?
C ++标准没有指定如何对字符串进行散列 - 它留给了各个编译器实现。因此,不同的编译器会产生不同的妥协 - 甚至是同一编译器的不同版本。
文档DavidPérezCabrera的答案链接解释了Java中的std::unordered_map
函数:
返回此字符串的哈希码。 String对象的哈希码计算为
hashCode
使用
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
算术,其中int
是字符串的s[i]
th 字符,i
是字符串的长度,并且n
表示取幂。 (空字符串的哈希值为零。)
这显然是字符串长度的O(N)。
答案 2 :(得分:2)
根据Java的实现,Hashtable使用key(String或Integer)的hashCode方法。 Hashtable String.hashCode Integer.hashCode
根据http://en.cppreference.com/w/cpp/utility/hash,C ++使用std::hash<std::string>
或std::hash<int>
,实现位于功能文件中(/ path / to / c ++ ... /include/c++/4.8/functional)
答案 3 :(得分:0)
哈希函数的复杂度永远不会为O(1)。如果字符串的长度为n,则复杂度肯定为O(n)。但是,如果您计算给定数组中的所有哈希,则无需第二次计算,并且始终可以通过比较预先计算的哈希来比较O(1)时间中的两个字符串。