C++ - 随机选择的字符串不选择它不止一次

问题描述:

我有一个满手每个对象中的每个包含多个串。现在它被设置为结构,每个结构都包含一个键1 ... n的映射,每个字符串一个(map<int,string> strs),如果存在更好的方法,可以更改这个结构。我需要随机访问所有这些字符而不重叠,并且知道我已经完成了。我怎么能做到这一点,无论是与地图或其他数据结构?谢谢。C++ - 随机选择的字符串不选择它不止一次

+0

多少次你需要列举那些字符串以随机顺序?一旦?很多次? –

+0

所有的字符串都是唯一的,还是每个对象中的地图都可以包含一个也在另一个对象地图中的字符串? –

+1

我认为你正在寻找“洗牌”。有大量的样本(通常搜索“洗牌张牌+语言”会给你很好的效果) –

一个可怕的解决办法,不这样做。对于大的候选矢量非常慢,这具有n平方的复杂度。 Shuffling更好,它具有线性复杂性。

std::vector<int> RandomThing(int number, int min, int max) 
{ 
    assert(!"RandomThing" && min < max); 
    std::vector<int> candidates; 
    for(int i=min; i<max; i++) 
     candidates.push_back(i); 

    std::vector<int> result; 
    for(int i=0; i<number;) 
    { 
     int candidate_index = rand() % candidates.size(); 
     result.push_back(candidates[candidate_index]); 

     std::vector<int>::iterator it = candidates.begin(); 
     std::advance(it, candidate_index); 
     candidates.erase(it); 
    } 
    return result; 
} 
+1

为什么不只是洗牌候选人矢量?另外,使用mod与'rand()'只是不好的。 –

+0

这是真的,只需要经过一次就可以快得多,而不必从矢量中移除东西(将算法转换为n平方)。对于那个很抱歉。将解决方案留在这里,以便人们可以看到一个不好的方式,但重写文本以反映它的坏处。关于rand()%X,唯一的问题是“是否足够好”。当然它有明显的趋势,但如果这不是问题,那么我认为没有问题。 – Bozemoto

下面是一个Fisher-Yates shuffle一些代码:

template <class T> 
std::vector<T> shuffle(std::vector<T> &vect) 
{ 
    std::vector<T> shuffled = vect; 
    for(int i = shuffled.size()-1; i >= 1; i--) { 
     int idx = rand() % (i+1); 
     T tmp = shuffled[idx]; 
     shuffled[idx] = shuffled[i]; 
     shuffled[i] = tmp; 
    } 
    return shuffled; 
} 

这将需要一个载体,并以随机顺序返回它的一个副本。如果你有一个字符串矢量,你可以使用它像这样(我使用C++ 11此处):

int main() 
{ 
    srand(time(NULL)); 
    std::vector<std::string> strs = {"foo", "bar", "baz", "stack", "overflow"}; 
    for(auto &str : shuffle(strs)) { 
     std::cout << str << std::endl; 
    } 
    return 0; 
} 

当然,如果你是懒惰的,像我一样,总是有random_shuffle( )函数<algorithm>

#include <iostream> 
#include <vector> 
#include <string> 
#include <algorithm> 

int main() 
{ 
    std::vector<std::string> strs = {"foo", "bar", "baz", "stack", "overflow"}; 
    std::random_device rd; 
    std::mt19937 g(rd()); // Use a good random number generaor 
    std::random_shuffle(strs.begin(), strs.end(), g); // this does the shuffle 
    for(auto &str : strs) { 
     std::cout << str << std::endl; 
    } 
    return 0; 
} 

希望这有助于!

+0

如果你想使用,同时仍然使用洗牌标准库指定一个更强大的RNG,使用['的std :: random_device'(http://en.cppreference.com/w/cpp/numeric/random/random_device )与罐头发生器(如['的std :: mt19937'](http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine)),然后用['的std ::洗牌首要一个'](http://en.cppreference.com/w/cpp/algorithm/random_shuffle),使用你的rng作为生成器参数。 – WhozCraig

+0

^确实!我将加入它。:) –

+0

附上:[见它活着](http://ideone.com/bN4wRH) – WhozCraig