无序映射只能使用16个字符串来最大化唯一的密钥

unordered_map maxes out unique keys only with 16 character strings

本文关键字:最大化 唯一 密钥 字符串 16个 映射 无序      更新时间:2023-10-16

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

在其当前形式中,当"for i循环"需要20000次迭代时,它将挂起datact=16384,尽管事实上有4^16个字符串使用ACTG。

但是。。如果字符串长度更改为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;
}

正如@us2012所说,问题在于你的PRNG,以及低阶比特的随机性差。这里有一个相关的报价:

在《C中的数字食谱:科学计算的艺术》(William H.Press,Brian p.Flannery,Saul A.Teukolsky,William T.Vetterling;纽约:剑桥大学出版社,1992年(第2版,第277页)中,发表了以下评论:

"如果你想生成一个介于1和10之间的随机整数,你应该总是使用高阶比特来完成,就像一样

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

而且从来没有类似的东西

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

(使用较低阶位)"

此外,正如其他人所指出的,你也可以使用更好、更现代的RNG。

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

我能想到的两个修复:

  • 不是生成随机数mod 4,而是生成它们mod 4^length并提取比特对00 -> A, 01 -> G, ...

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

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