元组序列的哈希函数-重复消除
Hash function for sequences of tuples - Duplicate elimination
我想消除元组序列的重复。这些序列如下所示:
1. (1,1)(2,5,9)(2,3,10)(2,1)
2. (1,2)(3,2,1)(2,5,9)(2,1)
3. (1,1)(2,5,9)(2,3,10)(2,1)
4. (2,1)(2,3,10)(2,5,9)(1,1)
5. (2,1)(2,3,10)(1,1)
6. (1,1)(2,5,9)(2,3,10)(2,2)
每个元组的条目数和每个序列的元组数都不同。由于我有很多序列,我最终想使用CUDA并行处理这些序列,我认为计算每个序列的哈希是识别重复序列的有效方法。
如何实现这样的hash
功能并且:两个不同序列产生相同最终哈希值的碰撞概率有多大?
我有两个不确定是否能满足的要求:
a( 这样的散列值可以即时计算吗?我想避免存储完整的序列,因此我想做这样的事情:
h = 0; // init hash
...
h = h + hash(1,1);
...
h = h + hash(2,5,9);
...
h = h + hash(2,3,10)
...
h = h + hash(2,1)
其中CCD_ 2是组合元组的散列的任何运算符。
b( 这样的散列可以独立于序列的"方向"吗?在上面的例子中,序列1.
和4.
由相同的元组组成,但顺序相反,但我喜欢将它们识别为重复。
对于哈希,您可以使用std::hash<std::size_t>
或您使用的任何(无符号(整数类型。碰撞概率在1.0/std::numeric_limits<std::size_t>::max()
附近,这是非常小的。为了提高可用性,您可以编写自己的元组哈希器:
namespace hash_tuple
{
std::size_t hash_combine(std::size_t l, std::size_t r) noexcept
{
constexpr static const double phi = 1.6180339887498949025257388711906969547271728515625;
static const double val = std::pow(2ULL, 4ULL * sizeof(std::size_t));
static const std::size_t magic_number = val / phi;
l ^= r + magic_number + (l << 6) + (l >> 2);
return l;
}
template <typename TT>
struct hash
{
std::size_t operator()(TT const& tt) const noexcept
{
return std::hash<TT>()(tt);
}
};
namespace
{
template <class TupleT, std::size_t Index = std::tuple_size<TupleT>::value - 1ULL>
struct HashValueImpl
{
static std::size_t apply(std::size_t seed, TupleT const& tuple) noexcept
{
seed = HashValueImpl<TupleT, Index - 1ULL>::apply(seed, tuple);
seed = hash_combine(seed, std::get<Index>(tuple));
return seed;
}
};
template <class TupleT>
struct HashValueImpl<TupleT, 0ULL>
{
static std::size_t apply(size_t seed, TupleT const& tuple) noexcept
{
seed = hash_combine(seed, std::get<0>(tuple));
return seed;
}
};
}
template <typename ... TT>
struct hash<std::tuple<TT...>>
{
std::size_t operator()(std::tuple<TT...> const& tt) const noexcept
{
std::size_t seed = 0;
seed = HashValueImpl<std::tuple<TT...> >::apply(seed, tt);
return seed;
}
};
}
因此,您可以编写类似的代码
using hash_tuple::hash;
auto mytuple = std::make_tuple(3, 2, 1, 0);
auto hasher = hash<decltype(mytuple)>();
std::size_t mytuple_hash = hasher(mytuple);
为了满足您的约束b
,我们需要为每个元组提供2个哈希,正常哈希和反向元组的哈希。因此,首先我们需要处理如何逆转一个:
template<typename T, typename TT = typename std::remove_reference<T>::type, size_t... I>
auto reverse_impl(T&& t, std::index_sequence<I...>)
-> std::tuple<typename std::tuple_element<sizeof...(I) - 1 - I, TT>::type...>
{
return std::make_tuple(std::get<sizeof...(I) - 1 - I>(std::forward<T>(t))...);
}
template<typename T, typename TT = typename std::remove_reference<T>::type>
auto reverse(T&& t)
-> decltype(reverse_impl(std::forward<T>(t),
std::make_index_sequence<std::tuple_size<TT>::value>()))
{
return reverse_impl(std::forward<T>(t),
std::make_index_sequence<std::tuple_size<TT>::value>());
}
然后我们可以计算我们的哈希
auto t0 = std::make_tuple(1, 2, 3, 4, 5, 6);
auto t1 = std::make_tuple(6, 5, 4, 3, 2, 1);
using hash_tuple::hash;
auto hasher = hash<decltype(t0)>();
std::size_t t0hash = hasher(t0);
std::size_t t1hash = hasher(t1);
std::size_t t0hsah = hasher(reverse(t0));
std::size_t t1hsah = hasher(reverse(t1));
如果hash_combine(t0hash, t1hash) == hash_combine(t1hsah, t0hsah)
你找到了你想要的。您可以很容易地将这种"内部元组哈希机制"应用于许多元组的哈希。在线玩吧!
相关文章:
- C++变量在调用 x64 程序集函数后重置为 0
- 变量始终在函数中重置为默认值
- 为什么我的 LogError 函数会重置 GetLastError?
- 重命名 win32api 函数以进行混淆
- 每个线程 C++ 保护以防止重入函数调用
- 如何在重命名函数 (c++) 中使用变量?
- 如何通过 boost::p ython 重命名构造函数的关键字参数
- 重排序重载的模板函数
- 是否可以使用类的析构函数内部函数来重置值?
- 为什么与函数相比,链接阶段没有类重定义错误?
- C++不使用"inline"或"static"无类函数的关键字时出现重定义链接错误
- 是包含线程局部变量重入的函数
- 当作用域中出现条件时,如何重置函数中的变量?
- std::unique_ptr 在虚拟析构函数上重置 SIGABRT
- 你能重命名Visual Studio Code for C++中的函数吗?
- 重置在 lambda 函数中捕获的共享指针
- C++ vector<pair<int,int>> std::all_of() 函数问题(重定向到头文件)
- C++如何将STDIN重定向到函数
- C++ 继承时重命名函数参数
- bind shared_ptr ::重置 - 找不到匹配的超载函数