【问题标题】:Generate hash for boost::dynamic_bitset and convert hash back to boost::dynamic_bitset为 boost::dynamic_bitset 生成哈希并将哈希转换回 boost::dynamic_bitset
【发布时间】:2018-02-05 10:39:50
【问题描述】:

我希望生成一个boost::dynamic_bitset 哈希,以便我可以将值存储在boost::bimaps 中。我尝试了以下代码,Test code here.

#include <iostream>
#include <boost/dynamic_bitset.hpp>
#include <unordered_map>
#include <boost/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/unordered_multiset_of.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/multiset_of.hpp>

#define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS

namespace boost {
    template <typename B, typename A>
    std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
        return boost::hash_value(bs.m_bits);
    }
    }

namespace bimaps = boost::bimaps;
typedef boost::bimap<bimaps::unordered_set_of<unsigned long long int>,
        bimaps::unordered_multiset_of<size_t> > bimap_reference;
typedef bimap_reference::value_type position;
bimap_reference reference_index_vector;

int main()
{

    std::string str = "1011010001101101000001101101000011111111011010000011011010000111111111110110100011011010000011011010000111111110110100000110110100001111111111";
    boost::dynamic_bitset<>  bits = boost::dynamic_bitset<> (str);
    std::cout << "bitmap " << bits << std::endl;
    std::cout << "Number of bits " << bits.count() << std::endl;

    size_t hash1 = boost::hash_value (bits);
    std::cout << "Hash value "  << hash1 << std::endl;


/* Insert hash value in bimap
 *
 */

//    reference_index_vector.insert(position(10000000000, hash1));
//    for( bimap_reference::const_iterator iter = reference_index_vector.begin(), iend = reference_index_vector.end();
//            iter != iend; ++iter ) {
//        std::cout << iter->left << " <--> "<< iter->right <<std::endl;
//    }

    return 0;
}

我得到了错误

在 /usr/include/boost/dynamic_bitset.hpp:15:0 中包含的文件中,从 3 开始:在 'std::size_t boost::hash_value(const boost::dynamic_bitset&) 的实例化中 [with B = long unsigned诠释; A = std::分配器; std::size_t = long unsigned int]': 34:40: 从这里需要 /usr/include/boost/dynamic_bitset/dynamic_bitset.hpp:422:17: 错误: 'boost::dynamic_bitset::buffer_type boost:: dynamic_bitset::m_bits' 是私有 buffer_type m_bits; ^ 16:37:错误:在此上下文中

不知道出了什么问题。

  1. 如何散列boost::dynamic_bitset
  2. 如何将哈希转换回原始位集。
  3. 所需的总空间(计数为 0 和 1 或仅 1)。以上代码仅由bits.count() 显示 80 位。我尝试了以下方法来生成哈希值,但不确定需要多少空间。

另外,我尝试通过以下代码生成bitset的哈希值

/*Generating hash by bitset
     * 
     */
    std::bitset<142> seq (str);
    std::hash<std::bitset<142>> hash_bitset;
    std::cout << "Bitset " << seq << std::endl;
    std::cout << "Hash value " << hash_bitset(seq) << std::endl; 

    #Bitset 1011010001101101000001101101000011111111011010000011011010000111111111110110100011011010000011011010000111111110110100000110110100001111111111
    #Hash value 4886653603414440856

【问题讨论】:

    标签: c++ boost hash


    【解决方案1】:

    好的,我发现对“散列”的本质有很多困惑,所以有一些友好的指示可以开始:

    Q. 2. 如何将哈希转换回原始位集。

    那是不可能的。哈希是有损摘要。仅当哈希是 Perfect Hash 时才能执行此操作,根据熵定律,如果 bitset 容量超过您平台上 size_t 的大小(通常为 32 或 64 位),则不会发生这种情况。

    Q.我也尝试通过...创建哈希

     std::bitset<142> seq (str);
     ....
    

    我希望你意识到std::bitset&lt;&gt; 是一个完全不同的类型,所以它与任务没有真正的关系。而且,由于它不是动态的,因此即使作为一种解决方法,它也对任务没有帮助。

    但最重要的是:

    散列表使用散列(如unordered_*&lt;&gt;),但它们不存储。哈希是有损摘要,仅用于在内部存储桶中获得良好的分布¹。对于实际的元素相等性,std::equal&lt;T&gt;仍然被使用。

    换句话说:

    typedef boost::bimap<bimaps::unordered_set_of<unsigned long long int>,
            bimaps::unordered_multiset_of<size_t> > bimap_reference;
    

    不适合创建 size_tunsigned long long² 以外的任何地图。如果你在那里存储事物的哈希值:

    reference_index_vector.insert(position(10000000000, hash1));
    

    ,您丢失了原始信息。无法从hash1 获取位集。

    编译器错误

    您的hash_value 实现错误地使用了dynamic_bitset&lt;&gt; 的私有成员。你不能,因为它不可访问。

    这是使用公共接口的std::hash&lt;&gt; 的简单实现:

    Live On Coliru

    #include <boost/dynamic_bitset.hpp>
    #include <boost/functional/hash.hpp>
    #include <unordered_map>
    #include <sstream>
    
    namespace std {
    
        template <typename Block, typename Alloc> struct hash<boost::dynamic_bitset<Block, Alloc> > {
            size_t operator()(boost::dynamic_bitset<Block, Alloc> const& bs) const {
                size_t seed = boost::hash_value(bs.size());
    
                std::vector<Block> blocks(bs.num_blocks());
                boost::hash_range(seed, blocks.begin(), blocks.end());
    
                return seed;
            }
        };
    
    }
    
    int main() {
        boost::dynamic_bitset<> x, y;
        x.resize(rand()%100, 1);
        y.resize(rand()%100, 0);
    
        std::unordered_map<boost::dynamic_bitset<>, std::string> m;
        m[x] = "x";
        m[y] = "y";
    }
    

    您可以改用此std::hash&lt;&gt; 特化并使用boost::bimap

    注意,使用公共接口不是最佳选择,因为它复制了Blocks(您也使用std::bitset&lt;&gt; hack 做到了这一点)。您可能对我之前为 boost::dynamic_bitset&lt;&gt; 所做的 Boost Serialization 实现感兴趣:


    ¹ 为简单起见,假设使用桶而不是“开放寻址”样式。同样的逻辑也适用于那里,但稍微复杂一些

    ²(顺便请说uintmax_tuint64_t

    【讨论】:

    • 感谢您的详细解答。我想如果我可以直接使用boost::dynamic_bitset作为bimap中的key,那么我就不需要插入hash值了。正如你所说,我试过 namespace bimaps = boost::bimaps; typedef boost::bimap&lt;bimaps::unordered_set_of&lt;size_t&gt;, bimaps::unordered_multiset_of&lt;boost::dynamic_bitset&lt;&gt; &gt; &gt; bimap_reference; typedef bimap_reference::value_type position; bimap_reference reference_index_vector; ,我得到了很多错误
    • 是的。您想将位集用作键。哈希是一个实现细节。让我创建一个示例......等等
    • 这是一个使用您的 bimap 的现场演示:Live On Coliru。关键是像我在答案中所说的那样使用std::hash&lt;&gt; 专业化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    • 2019-05-23
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 2015-09-09
    相关资源
    最近更新 更多