簡體   English   中英

定義自定義哈希函數以增強Boost哈希圖

[英]Defining a custom hash-function for boost hash map

我對C ++非常陌生,我需要將一些用C編寫的代碼轉換為C ++。 問題在於,我很難即時理解C ++語法。 我希望使用無序的Boost哈希圖,並且希望定義自己的哈希函數。 我查找了如何執行此操作,並遇到了這段代碼:

struct ihash
    : std::unary_function<std::string, std::size_t>
{
    std::size_t operator()(std::string const& x) const
    {
         std::size_t seed = 0;
         std::locale locale;

         for(std::string::const_iterator it = x.begin();
            it != x.end(); ++it)
         {
            boost::hash_combine(seed, std::toupper(*it, locale));
         }

         return seed;
    }
};

Which you can then use in a case insensitive dictionary:

boost::unordered_map<std::string, int, ihash, iequal_to> idictionary;

我有以下哈希函數:

unsigned long hash (unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while(c = *str++)
    hash  = ((hash << 5) + hash) + c; /* hash + 33 + c */
    hash %= outer_relation->hash_table.bucket_count();

    return hash;
}

有人可以幫助我進行轉換嗎? 特別是,種子和聯合收割機負責什么?

第一個( ihash )是通用哈希,以函數對象的形式實現。 這有幾個優點:

  • 它是通用的,意味着您可以將其與容量/負載因數不同的哈希表一起使用,而無需了解/關心內部組織
  • 因為它是一個可調用對象,並且它是默認可構造的,所以您實際上可以“僅”實例化無序映射:

     boost::unordered_map<std::string, int, ihash, iequal_to> idictionary; 

    然后它將使用默認構造的ihash實例作為哈希函數( iequal_to ,與iequal_to相同)。

第二個看起來像是哈希函數,被硬連接到哈希表實現中。 顯然,此哈希表實現假定所有鍵都必須為unsigned char* ,並且它派生存儲桶索引作為哈希實現的一部分。 筆記:

  • 您不能輕松地將其用於默認可構造的地圖:

     boost::unordered_map<std::string, int, unsigned long(*)(unsigned char*), iequal_to> idictionary; 

    因為這將導致哈希函數的nullptr實例。 因此,您最終總是將&hash傳遞給構造函數重載。 只要原型匹配,就很難推理代碼,因為傳遞錯誤的函數指針並非不可能

  • 此函數假定鍵不能包含嵌入的NUL字符(這不是對std::string的限制

  • 此函數不是const正確的(意味着除非添加const,否則您無法使其適用於mapunordered_map ,例如size_t (*)(unsigned char const*) )。

除了這些觀察結果之外,這兩個函數基本上都完成相同的工作,其中ihash會根據全局C ++語言環境折疊大小寫( 請參閱docs )。

我不確定您被困在哪里,因為您的樣本看起來應該比較完整? 因此,這里有一些獨立的示例,以防您被卡住:

#include <boost/unordered_map.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <iostream>

namespace hash_examples
{
    struct iequal_to
        : std::binary_function<std::string, std::string, bool>
    {
        iequal_to() {}
        explicit iequal_to(std::locale const& l) : locale_(l) {}

        template <typename String1, typename String2>
        bool operator()(String1 const& x1, String2 const& x2) const
        {
            return boost::algorithm::iequals(x1, x2, locale_);
        }
    private:
        std::locale locale_;
    };

    struct ihash
        : std::unary_function<std::string, std::size_t>
    {
        ihash() {}
        explicit ihash(std::locale const& l) : locale_(l) {}

        template <typename String>
        std::size_t operator()(String const& x) const
        {
            std::size_t seed = 0;

            for(typename String::const_iterator it = x.begin();
                it != x.end(); ++it)
            {
                boost::hash_combine(seed, std::toupper(*it, locale_));
            }

            return seed;
        }
    private:
        std::locale locale_;
    };
}

int main()
{
    using namespace hash_examples;
    boost::unordered_map<std::string, int, ihash, iequal_to> map;
    map.emplace("one",   1);
    map.emplace("two",   2);
    map.emplace("three", 3);

    std::cout << map.at("TWO");
}

請注意, hash_examples直接來自http://www.boost.org/doc/libs/1_55_0/libs/unordered/examples/case_insensitive.hpp

在Coliru上實時觀看

如果要使用自己的哈希,為什么不實現ihash這樣的東西呢?

struct ihash : std::unary_function<std::string, std::size_t> {
  std::size_t operator()(std::string const& value) const {
    std::size_t hash = 5381;
    const char* str = value.c_str();
    int c;
    while(c = *str++)
    hash  = ((hash << 5) + hash) + c; /* hash + 33 + c */
    hash %= outer_relation->hash_table.bucket_count();
    return hash;
  }
}

暫無
暫無

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

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