Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 无序多集的hash/crc算法_C++_Algorithm_Hash_Crc - Fatal编程技术网

C++ 无序多集的hash/crc算法

C++ 无序多集的hash/crc算法,c++,algorithm,hash,crc,C++,Algorithm,Hash,Crc,假设我想创建一个无符号int的无序多集的无序集。为此,我需要创建一个散列函数来计算无序多集的散列。事实上,这对CRC也有好处 一个明显的解决方案是将项目放入向量中,对它们进行排序并返回结果的散列。这似乎管用,但很贵 另一种方法是对值进行异或运算,但很明显,如果有一个项两次或没有,结果将是相同的——这是不好的 我有一个应用程序,它可以为数千个集合和相对较大的集合实现这一千个集合。将内部多集合实现为一个值->计数哈希映射 这将允许您通过以下方式避免偶数个元素通过xor抵消的问题:您不必对每个元素进行

假设我想创建一个无符号int的无序多集的无序集。为此,我需要创建一个散列函数来计算无序多集的散列。事实上,这对CRC也有好处

一个明显的解决方案是将项目放入向量中,对它们进行排序并返回结果的散列。这似乎管用,但很贵

另一种方法是对值进行异或运算,但很明显,如果有一个项两次或没有,结果将是相同的——这是不好的


我有一个应用程序,它可以为数千个集合和相对较大的集合实现这一千个集合。

将内部多集合实现为一个值->计数哈希映射


这将允许您通过以下方式避免偶数个元素通过xor抵消的问题:您不必对每个元素进行xor运算,而是根据计数和值构造一个新的数字(例如,将它们相乘),然后可以使用xor构建完整的哈希

由于它是一个多集,您希望相同的多集的哈希值相同,这些多集的表示可能以不同的顺序显示、添加或删除相同的元素。然后,您希望哈希值是可交换的、易于更新的,并且随着元素的每次更改而更改。您还希望两个更改不会轻易取消它们对散列的影响

除最后一个条件外,满足所有条件的一个操作是加法。只需对元素求和即可。要保持和有界,请对哈希值的大小进行和模运算。(例如,64位散列的模264。)要确保插入或删除零值会更改散列,请先为每个值添加一个


这个总和的一个缺点是两个变化很容易被抵消。例如,将1 3替换为2 2。为了解决这个问题,您可以使用相同的方法,对条目的多项式求和,仍然保持交换性。例如,您可以对x2+x+1求和,而不是对x+1求和。现在,用相同的和来设计一组变化就更难了。

这里有一个合理的哈希函数,用于
std::unordered\u multiset
如果将计算取为一个大素数会更好,但这个想法是正确的

#include <iostream>
#include <unordered_set>

namespace std {
    template<>
    struct hash<unordered_multiset<int>> {
        typedef unordered_multiset<int> argument_type;
        typedef std::size_t result_type;

        const result_type BASE = static_cast<result_type>(0xA67);

        result_type log_pow(result_type ex) const {
            result_type res = 1;
            result_type base = BASE;
            while (ex > 0) {
                if (ex % 2) {
                    res = res * base;
                }
                base *= base;
                ex /= 2;
            }
            return res;
        }

        result_type operator()(argument_type const & val) const {
            result_type h = 0;
            for (const int& el : val) {
                h += log_pow(el);
            }
            return h;
        }
    };
};

int main() {
    std::unordered_set<std::unordered_multiset<int>> mySet;
    std::unordered_multiset<int> set1{1,2,3,4};
    std::unordered_multiset<int> set2{1,1,2,2,3,3,4,4};
    std::cout << "Hash 1: " << std::hash<std::unordered_multiset<int>>()(set1) 
              << std::endl;
    std::cout << "Hash 2: " << std::hash<std::unordered_multiset<int>>()(set2) 
              << std::endl;
    return 0;
}

当它是素数p时,碰撞的次数与1/p成正比。我不确定二次幂的分析是什么。插入/删除整数x时,通过添加/减去基数^x,可以有效地更新哈希值。

是否可以修改多集,以便它们在插入/删除时重新计算哈希值?然后,如果需要多次查找,则不必不断重新计算哈希值。从技术上讲,是的,但这有什么帮助?因为缓存的值可以简单地读取,所以不需要计算数千次。我有数千个集合,我不会一次又一次地对同一集合执行此操作。但这是否正确。例如,对于16位,如果我从0xFFFF开始,如果添加另一个0xFFFF,0xFFFF+0xFFFF=0x7FFF,那么如果我删除它0x7FFF-0xFFFF=0x7FFF-初始值和结束值不相同。模2^16:0xFFFF+0xFFFF=0xFFFE,0x7FFF-0xFFFF=0x8000。当然,0xFFFE-0xFFFF=0xFFFF。
Hash 1: 2290886192
Hash 2: 286805088