Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.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++ 将值规格化为较小的范围_C++_Linux_Algorithm - Fatal编程技术网

C++ 将值规格化为较小的范围

C++ 将值规格化为较小的范围,c++,linux,algorithm,C++,Linux,Algorithm,说明 我有一组相当大的(字符串、字符串、字符串)唯一元组(大约40mln,但可以变大)。对于每个元组,我计算一个无符号int值。我希望将这些值存储在某个位置,以便在生成它们之后可以重用它们(即使在应用程序宕机之后,内存存储也是不可能的,不幸的是,数据库也是如此) 起初,我将它们作为元组(string,string,string,value)存储在一个文件中,但读取40mln记录需要时间(我几乎立即需要它) 我决定首先计算每个(字符串、字符串、字符串)元组的散列值,然后将其标准化为[0,n](其中

说明

我有一组相当大的(字符串、字符串、字符串)唯一元组(大约40mln,但可以变大)。对于每个元组,我计算一个无符号int值。我希望将这些值存储在某个位置,以便在生成它们之后可以重用它们(即使在应用程序宕机之后,内存存储也是不可能的,不幸的是,数据库也是如此)

起初,我将它们作为元组(string,string,string,value)存储在一个文件中,但读取40mln记录需要时间(我几乎立即需要它)

我决定首先计算每个(字符串、字符串、字符串)元组的散列值,然后将其标准化为[0,n](其中n是值的数量),并仅将值以排序顺序(按标准化散列值排序)存储在二进制文件中。之后,我可以简单地将mmap()映射到这个文件,并使用mmap[normalize(hash(string,string,string))]获取值

我的哈希函数非常简单,但速度很快,在我的情况下也能正常工作(没有注意到任何冲突):

n-我的标准化范围的上限(因此大约40mln,我不取n(n-下限),因为下限=0)

max\u value旧集合的最大值(在我的例子中,UINT\u max,min\u value=0,因此我不将其包括在等式中)

问题

我的散列函数在0到4294967295(无符号整数)的范围内不会产生均匀分布的值(甚至不知道它是如何做到的)。由于这一点,在标准化之后,我有相当多的冲突导致数据丢失(覆盖相同数组索引下的值)

有没有聪明的方法来做我想做的事情,但没有这些冲突

我完全知道可能会发生碰撞。问题是,在我的方法中,它们往往发生得太频繁了。我的散列范围比我的元素数大100倍,所以我猜可能有办法做到这一点,但我还没有弄清楚怎么做

解决方案
最后,我将我的散列改为杂音散列,将我的规范化方法改为简单的“modulo newRange”,并更改了文件的格式(我现在存储所有数据(字符串值))-文件现在相当大,但由于它,我能够实现一个简单的冲突检测机制(双重散列).

并非总是可以将哈希值规范化为唯一的[0..n]值

我可以向您建议两种方法:

  • 对文件进行排序并使用二进制搜索而不是映射。(LogN 复杂性)
  • 用索引折皱第二个文件,并在范围内实现哈希表 [0..5n](5n可能会被比n大的任何其他数字更改)

  • 事实上,我很惊讶,在规范化散列值的范围之前,没有发生冲突。看起来您正在使用一个非标准化的[0,2^32)。查看生日问题图表,与4*10^7个元素发生冲突的概率应高于75%。在任何情况下,将哈希输出规格化为等于元素集大小的范围实际上可以保证非平凡数量的冲突。除非您愿意为哈希值使用计数器我不知道你怎么能避免这种情况

    编辑:查看您的编辑。即使范围是元素数的100倍(约为4*10*9),您仍然可能会遇到大量碰撞。如上所述,一次或多次碰撞的概率远远超过75%

    我有两个建议:

    选择其他哈希函数

    正如您所指出的,虽然您的哈希函数很快,但它不会在[0,2^32]范围内随机分布值。有几个哈希函数都很快,而且在整个哈希函数范围内分布哈希值的效果更好。我过去使用的一个是

    使用更大的范围


    使用较大的范围应该可以降低冲突风险。再次查看图表,64位似乎足以将冲突风险降低到10^-6以下。在这种情况下,MurrueHash64a和MurrueHash64b变体将非常有用。

    据我所知,您需要一个唯一的哈希(实际上不可能:):

    hashCode()提供了一个32位的哈希代码

    如果您想要(比如)一个64位哈希代码,您可以自己轻松地实现它

    如果需要字符串的加密哈希,Java crypto库包括MD5、SHA-1等的实现。通常需要将字符串转换为字节数组,然后将其馈送到哈希生成器/摘要生成器。例如,请参阅@Boris Pavlović的答案

    如果你想要一个唯一的哈希代码,那你就倒霉了。哈希和哈希代码是非唯一的


    长度为N的Java字符串有65536^N个可能的状态,需要一个16*N位的整数来表示所有可能的值。如果您编写的哈希函数生成的整数范围较小(例如小于16*N位),您最终会发现多个字符串散列到同一个整数的情况;即散列码不能唯一。这被称为鸽子洞原理,并且有一个直接的数学证明。(您无法与数学抗争并获胜!)

    您是说您正在使用此标准化:

    ((unsigned int) n * hash) / max_value
    
    你说
    max\u value
    UINT\u max

    “最大值-旧集的最大值(UINT_max)”

    hash
    被声明为
    unsigned int

    好的,你知道,那么上面只能产生值0和1,这保证了碰撞

    < >你知道C++中的整数和浮点除法<强> > > < /P> 如果没有,我建议你去买


    顺便说一下,像“(unsigned int)之类的强制转换是创建bug.T的可靠方法
    ((long) n * hash) / max_value
    
    ((unsigned int) n * hash) / max_value