【问题标题】:unordered_map maxes out unique keys only with 16 character stringsunordered_map 仅使用 16 个字符串最大化唯一键
【发布时间】:2013-01-21 05:39:06
【问题描述】:

此代码仅使用 A、C、T、G 生成一个随机的 16 个字符的字符串。然后它检查这个序列是否在散列(unordered_map)中,如果没有,则将其插入并指向一个虚拟占位符。

在当前形式中,当“for i 循环”需要 20000 次迭代时,它会在 datact=16384 处挂起,尽管 ACTG 有 4^16 个字符串。

但是.. 如果字符串长度更改为 8、9、10、11.. 到 15 或 17、18.. 它正确地迭代到 20000。为什么 unordered_map 拒绝散列新序列,但只有当那些序列长 16 个字符?

#include <string>
#include <vector>
#include <unordered_map>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>

using namespace std;


int main(int argc, char* argv[])
{
    string funnelstring;

    srand ( time(NULL) );

    const int buffersize=10000;
    int currentsize=buffersize;

    int datact=0;

    vector <unsigned int> ctarr(buffersize);

    vector <char> nuc(4);
    nuc[0]='A';
    nuc[1]='C';
    nuc[2]='T';
    nuc[3]='G';

    unordered_map <string,unsigned int*> location;

    unsigned int sct;
    sct=1;

    for (int i=0;i<20000; i++)
    {
        do
        {
            funnelstring="";
            for (int i=0; i<16; i++)
            {   // generate random 16 nucleotide sequence
                funnelstring+=nuc[(rand() % 4)];
            }
        } while (location.find(funnelstring) != location.end()); //asks whether this key has been assigned

        ctarr[datact]=sct;
        location[funnelstring]=&ctarr[datact]; //assign current key to point to data count
        datact++;
        cout << datact << endl;

        if (datact>=currentsize)
        {
            ctarr.resize(currentsize+buffersize);
            currentsize+=buffersize;
        }
    }

    return 0;
}

【问题讨论】:

  • 我认为标题具有误导性。我很确定这与unordered_map 本身没有任何关系。你从哪里得到“它拒绝散列新序列”的想法?我会指出 PRNG 是最有可能的罪魁祸首。
  • 好的,很有趣。有趣的是我试图重现一个几乎相同的错误,但序列不是随机生成的。看来我不小心在这段代码中引入了一个新问题,对于虚假广告,我深表歉意。这里的协议是什么?考虑解决这个子问题,并可能打开一个“完整”问题的新问题?
  • 是的,尽管您应该尽量缩小范围,即提供一个重现您的问题但没有不必要细节的代码示例(作为记录,我认为您的示例适用于这个问题在这方面非常好)。
  • 您当然可以使用"AAACATAGCACCCTCGTATCTTTGGAGCGTGG"[2*(rand()%16] 一次获取两个碱基。这使用较少的随机数并使用每个数字中的更多随机位。即便如此,您仍然应该得到比当前更好的 RNG。

标签: c++ hash key unordered-map


【解决方案1】:

正如@us2012 所说,问题在于您的 PRNG,以及低位随机性差。这是一个相关的报价:

在 C 中的数值食谱:科学计算的艺术(William H. Press、Brian P. Flannery、Saul A. Teukolsky、William T. Vetterling;纽约:剑桥大学出版社,1992 年(第 2 版,p. 277)),制作了以下 cmets:

"如果你想生成一个介于 1 和 10 之间的随机整数,你应该总是使用高位来实现,如

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));

从来没有类似的东西

j = 1 + (rand() % 10);

(使用低位)。”

另外,正如其他人所指出的,您还可以使用更好、更现代的 RNG。

【讨论】:

  • 这句话应该在上下文中考虑。 如果您的 PRNG 来自 80 年代,那么建议成立。正如us2012 指出的那样,C++11 有&lt;random&gt;,这要好得多。特别是它有更好的 PRNG 和 std::uniform_int_distribution
【解决方案2】:

罪魁祸首很可能是您的随机数生成器,即来自 PRNG 的随机数序列变得周期性 (mod 4) 太快(大多数随机数生成器确实产生 -随机数,因此名称为 PRNG)。因此,您的do...while 循环永远不会退出,因为它无法使用提供的随机数找到新的核苷酸序列。

我能想到的两个修复方法:

  • 不是生成随机数mod 4,而是生成它们mod 4^length并提取位对00 -&gt; A, 01 -&gt; G, ...

  • 使用更好的 PRNG,例如 std::mersenne_twister_engine

(免责声明:我不是随机数方面的专家。对于关键任务系统、加密要求等,请不要依赖此建议。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 2012-07-06
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    相关资源
    最近更新 更多