簡體   English   中英

如何使用 C++ 將字符串散列到 int?

[英]How can I hash a string to an int using c++?

我必須編寫自己的哈希函數。 如果我只想制作將字符串中的每個字母映射到數值(即 a=1, b=2, c=3, ...)的簡單散列函數,有沒有一種方法可以在一個字符串而不必先將其轉換為 c 字符串來查看每個單獨的字符? 有沒有更有效的方法來散列字符串?

根據個人經驗,我知道這有效並產生了良好的發行版。 (抄襲自http://www.cse.yorku.ca/~oz/hash.html ):

djb2

該算法 (k=33) 多年前由 dan Bernstein 在 comp.lang.c 中首次報道。 該算法的另一個版本(現在受到伯恩斯坦青睞)使用異或: 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 這樣做),那么您可以改為返回哈希模的 abs 一個素數。 所以與其

    return (h > 0 ? h : -h) % N_BUCKETS;

對於最后一行。

您可以使用[]運算符檢查 std::string 中的每個字符。 但是,您可以查看Boost::Functional/Hash以獲得關於更好的散列方案的指導。 此處還有一個 c 中的散列函數列表。

C++11 附帶了一個標准的字符串散列函數。

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 友好。 我必須刪除參數的無符號限定符,以便它可以處理文字字符串。

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;
}

將字符異或在一起,一次四個。

#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;
}

小字符串的另一種方法:

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;
}

您可以使用成員函數operator[]或字符串類或迭代器的at來訪問字符串對象的單個字符,而無需將其轉換為 c 樣式的字符數組。

要將字符串對象散列為整數,您必須訪問字符串對象的每個單獨字符,您可以這樣做:

for (i=0; i < str.length(); i++) {
    // use str[i] or str.at(i) to access ith element.
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM