为boost :: dynamic_bitset生成哈希并将哈希值转换回boost :: dynamic_bitset

时间:2017-08-28 07:57:44

标签: c++ boost hash

我希望生成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&amp;)[B = long unsigned int; A = std :: allocator; std :: size_t = long unsigned int]':34:40:从这里需要/usr/include/boost/dynamic_bitset/dynamic_bitset.hpp:422:17:错误:'boost :: dynamic_bitset&lt;&gt; :: buffer_type boost: :dynamic_bitset&lt;&gt; :: m_bits'是私有buffer_type m_bits; ^ 16:37:错误:在此上下文中

不确定出了什么问题。

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

    生成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
    

1 个答案:

答案 0 :(得分:3)

好吧,我发现了很多关于“哈希”本质的混淆,所以有一些友好的指示可以开始:

  

问。 2.如何将散列转换回orignial bitset。

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

  

问。我还尝试通过...创建哈希

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

我希望你意识到std::bitset<>是一种完全不同的类型,所以它与任务没有关系。并且,由于它不是动态的,因此即使作为一种解决方法,它对任务也没那么有用。

但最重要的是:

散列表(例如unordered_*<>使用 但是未存储。哈希是有损消化,只用于在内部桶上获得良好的分布¹。对于实际的元素相等性,std::equal<T> 仍然使用。

换句话说:

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得到bitset。

编译器错误

您的hash_value实施错误地使用了dynamic_bitset<>的私人成员。你不能,因为它无法访问。

以下是使用公共接口的std::hash<>的简单实现:

<强> 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<>专门化,并使用boost::bimap

注意,使用公共接口并不是最佳选择,因为它会复制Block s(您也使用std::bitset<> hack执行了此操作)。您可能对我之前为boost::dynamic_bitset<>所做的Boost序列化实现感兴趣:

¹为简单起见,假设桶代替“开放寻址”风格。同样的逻辑适用于那里,但有点复杂

²(顺便说一下,请说uintmax_tuint64_t