我需要编写自己的哈希函数。如果我想要简单的哈希函数,将字符串中的每个字母映射到数字值(例如a=1,b=2,c=3,...),是否有一种方法可以在不必先将其转换为C字符串以查看每个单独字符的情况下对字符串执行此哈希?有没有更有效的哈希字符串的方法?
根据个人经验,我知道这个方法行之有效且产生出良好的分布。(从http://www.cse.yorku.ca/~oz/hash.html盗用):
djb2
这个算法(k=33)是由Dan Bernstein多年前在comp.lang.c上首次报告的。这个算法的另一个版本(现在被Bernstein青睐)使用异或运算:hash(i) = hash(i - 1) * 33 ^ str[i];数字33的魔力(为什么它比许多其他常量,无论是否为质数,都运行得更好)从未得到充分的解释。
unsigned long hash(unsigned char *str) {
unsigned long hash = 5381;
int c;
while (c = *str++) {
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}
关于第一个问题,当然可以,例如:
int hash = 0;
int offset = 'a' - 1;
for(string::const_iterator it=s.begin(); it!=s.end(); ++it) {
hash = hash << 1 | (*it - offset);
}
关于第二个问题,有很多更好的方法来哈希字符串。例如,可以查看这里提供的一些C示例(可以轻松地按照上面代码片段的方式转换为C ++)。
以下是我在Stroustrup的书中找到的C(++)哈希函数:
int hash(const char *str)
{
int h = 0;
while (*str)
h = h << 1 ^ *str++;
return h;
}
如果您将其用作哈希表(Stroustrup就是这样做的),则可以返回哈希取模质数的绝对值。因此,代码可以改为:
return (h > 0 ? h : -h) % N_BUCKETS;
对于最后一行。
h
等于 INT_MIN
,对 -h
进行求值会导致未定义的行为。更好的方法是使用无符号数进行哈希处理。 - fredoverflow您可以使用[]
运算符检查std::string中的每个字符。但是,您可以查看Boost::Functional / Hash以获取更好的哈希方案指导。此外,在c中还有一个散列函数列表,位于这里。
https://en.cppreference.com/w/cpp/string/basic_string/hash
#include <string>
#include<functional> // hash
int main(){
std::string s = "Hello";
std::size_t hash = std::hash<std::string>{}(s);
}
我只是发布了一个对Arnestig的djb2算法进行改进的版本,以便支持constexpr。我不得不移除参数的unsigned限定符,这样它才能与字面字符串一起使用。
constexpr unsigned long hash(const char *str) {
unsigned long hash = 5381;
while (int c = *str++) {
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}
小字符串的另一种方式:
int hash(const char* str) {
int hash = 0;
int c = 0;
while (c < std::strlen(str)) {
hash += (int)str[c] << (int)str[c+1];
c++;
}
return hash;
}
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
// a variation on dan bernstein's algorithm
// [http://www.cse.yorku.ca/~oz/hash.html]
template<typename Int>
struct hash {
hash() : acc(5381) { }
template<typename Ch>
void operator()(Ch ch) { acc = ((acc << 5) + acc) ^ ch; }
operator Int() const { return acc; }
Int acc;
};
int main(int argc, char* argv[])
{
string s("Hellp, world");
cout << hex << showbase
<< for_each(s.begin(), s.end(), hash<unsigned long long>()) << '\n';
return 0;
}
每次将四个字符进行异或操作。
您可以使用字符串类的成员函数operator[]或at,或迭代器来访问字符串对象的单个字符,而无需将其转换为C风格的字符数组。
要将字符串对象哈希为整数,您需要访问字符串对象的每个单独字符,可以按如下方式进行:
for (i=0; i < str.length(); i++) {
// use str[i] or str.at(i) to access ith element.
}
str.length()
,特别是对于在循环期间不会更改的字符串进行哈希。此外,考虑直接使用 str.c_str()
进行操作,以避免任何函数调用。字符串以 NULL
字符结尾。 - CodeAngry
*2
和|
来创建一个滑稽可笑的哈希值;-) - Steve Jessop