从数字和字母表中快速生成大量随机字符串

时间:2013-10-22 10:40:01

标签: c++ algorithm random shuffle

我必须从“az”,“AZ”和“0-9”中随机生成集(10k甚至更多)字符串,其大小为32个字符。 。

到目前为止,我的脑海中有以下代码(O(N * 32)),但我想知道是否有更好的方法可以做到这一点。

int N = 10000;           
vector<string> vecStr;

for (int index=0; index<N; index++)
{
  string str;
  for (int i = 0; i < 32; ++i)
  {
    int randomChar = rand()%(26+26+10);        
    if (randomChar < 26)
      str += 'a' + randomChar;
    else if (randomChar < 26+26)
      str += 'A' + randomChar - 26;
    else
      str += '0' + randomChar - 26 - 26;
  }
  vecStr.push_back(str);
} 

5 个答案:

答案 0 :(得分:6)

你不会找到比O(N * len)更好的解决方案,其中N是字符串的数量,len是其中每个的长度。也就是说,在某些地方,我确信我可以通过编写最密集的代码来获得失去光泽的贴纸:

#include <iostream>
#include <iterator>
#include <vector>
#include <random>
#include <algorithm>

int main()
{
    static const char alphabet[] =
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "0123456789";

    static const size_t N_STRS = 10000;
    static const size_t S_LEN = 32;

    std::random_device rd;
    std::default_random_engine rng(rd());
    std::uniform_int_distribution<> dist(0,sizeof(alphabet)/sizeof(*alphabet)-2);

    std::vector<std::string> strs;
    strs.reserve(N_STRS);
    std::generate_n(std::back_inserter(strs), strs.capacity(),
        [&] { std::string str; 
              str.reserve(S_LEN); 
              std::generate_n(std::back_inserter(str), S_LEN,
                   [&]() { return alphabet[dist(rng)];}); 
              return str; });
    std::copy(strs.begin(), strs.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
    return 0;
}

输出(为简洁省略了9990行= P)

MRdeOWckfKy8GTFt0YmQMcM6SABJc934
XvdcatVsv6N9c1PzQGFFY6ZP943yIrUY
xpHzxUUyAizB6BfKldQzoePrm82PF1bn
kMUyPbflxk3yj3IToTFqYWnDq6aznKas
Ey0W5SF37VaeEY6PxWsBoxlNZTv9lOUn
iTx7jFRTHHW6TfYl7N3Hne4yu7kgAzp5
0ZamlaopjLyEvJbr6fzJPdXmjLOohtKh
6ZYeqj47nCMYKj0sCGl2IHm28FmvuH8h
oTDYRIA1trN1A2pQjsBwG3j9llzKIMhw
5zlpvSgTeLQ38eFWeSDoSY9IHEMHyzix

请注意,您可能会惊讶地发现它的速度有多快。引擎盖下发生了很多事情。最后,这使用了C ++ 11随机库,特别是均匀分布,消除了传统rand() % n解决方案对特定n通常遇到的模偏差。

答案 1 :(得分:2)

您可能会考虑C ++ 11中提供的random number generators and distributions

如,

const char alphanumeric[] = "0 .. 1A .. Za.. z";

std::default_random_engine rng;
std::uniform_int_distribution<> dist (0, sizeof(alphanumeric) - 1);

...

for (int i = 0; i < 32; i++)
    str += alphanumeric[dist(rng)];

我添加vecStr.push_back(str)可能不会那么昂贵,因为它可能会使用std::string对象的移动分配std::string对象在其实现中通常也有“短字符串”优化(SSO)。

vector<string> vecStr (N);
...
vecStr[index] = std::move(str);

答案 2 :(得分:1)

你不能做得比O(mn)更好(其中m是字符串的长度(此处为= 32),n是字符串的数量。)

原因是输出大小为O(mn),逻辑上需要至少O(1)对输出中的每个字符起作用。

请注意,您的算法可能比O(mn)慢一些,因为字符串的某些重新分配可能会发生。为防止这种情况,您可以使用string::reserve

int M = 32;
...
  string str;
  str.reserve(M);
  for (int i = 0; i < M; ++i)
...

但鉴于M只有32,它不太可能产生显着差异。

而且,只是为了好玩,以下是您的代码的变体:

int N = 10000, M = 32;
vector<string> vecStr;
string alphabet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
for (int index = 0; index < N; index++)
{
  string str;
  str.reserve(M);
  for (int i = 0; i < M; ++i)
  {
    str += alphabet[rand() % alphabet.length()];
  }
  vecStr.push_back(str);
}

Live demo

答案 3 :(得分:0)

考虑为随机字符串使用预分配缓冲区。 此外,您可能会预生成一些随机块并置换它们。

答案 4 :(得分:0)

在算法效率方面没有太大改进,但我建议

void random_string(char *s, int len=32) {
static const char alphabet[] =
    "0123456789"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz";

for (int i = 0; i < len; ++i) {
    s[i] = alphabet[rand() % (sizeof(alphabet) - 1)];
  }

 s[len] = '\0';
}