地图中的随机元素

时间:2008-10-01 17:45:22

标签: c++ random map

从地图中选择随机元素的好方法是什么? C ++。据我所知,地图没有随机访问迭代器。密钥很长,地图人口稀少。

9 个答案:

答案 0 :(得分:40)

map<...> MyMap;
iterator item = MyMap.begin();
std::advance( item, random_0_to_n(MyMap.size()) );

答案 1 :(得分:12)

如果地图很小或者你不经常需要随机值,我喜欢詹姆斯的回答。如果它很大并且您经常这样做足以使速度变得重要,那么您可以保留一个单独的键值向量来从中选择一个随机值。

map<...> MyMap;
vector<...> MyVecOfKeys; // <-- add keys to this when added to the map.

map<...>::key_type key = MyVecOfKeys[ random_0_to_n(MyVecOfKeys.size()) ];
map<...>::data_type value = MyMap[ key ];

当然,如果地图真的很大,你可能无法存储这样的所有密钥的副本。如果你能负担得起,虽然你可以在对数时间内获得查找的优势。

答案 2 :(得分:6)

可能会绘制一个随机密钥,然后使用lower_bound查找实际包含的最近密钥。

答案 3 :(得分:4)

继续使用预构造地图和快速随机查找的ryan_s主题:我们可以使用迭代器的并行映射代替向量,这可以加快随机查找速度。

map<K, V> const original;
...

// construct index-keyed lookup map   
map<unsigned, map<K, V>::const_iterator> fast_random_lookup;
map<K, V>::const_iterator it = original.begin(), itEnd = original.end();
for (unsigned i = 0; it != itEnd; ++it, ++i) {
  fast_random_lookup[i] = it;
}

// lookup random value
V v = *fast_random_lookup[random_0_to_n(original.size())];

答案 4 :(得分:2)

如果您的地图是静态的,那么使用向量代替地图,使用向量按键顺序存储键/值对,使用二进制搜索在log(n)时间内查找值,使用向量索引获取随机对在恒定的时间。您可以将矢量/二进制搜索包装为具有随机访问功能的地图。

答案 5 :(得分:1)

也许您应该考虑Boost.MultiIndex,但请注意它有点过于沉重。

答案 6 :(得分:0)

以下是所有地图项必须以随机顺序访问的情况。

  1. 将地图复制到矢量。
  2. 随机播放矢量。
  3. 在伪代码中(它密切反映了以下C ++实现):

    import random
    import time
    
    # populate map by some stuff for testing
    m = dict((i*i, i) for i in range(3))
    # copy map to vector
    v = m.items()
    # seed PRNG   
    #   NOTE: this part is present only to reflect C++
    r = random.Random(time.clock()) 
    # shuffle vector      
    random.shuffle(v, r.random)
    # print randomized map elements
    for e in v:
        print "%s:%s" % e, 
    print
    

    在C ++中:

    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <vector>
    
    #include <boost/date_time/posix_time/posix_time_types.hpp>
    #include <boost/foreach.hpp>
    #include <boost/random.hpp>
    
    int main()
    {
      using namespace std;
      using namespace boost;
      using namespace boost::posix_time;
    
      // populate map by some stuff for testing
      typedef map<long long, int> Map;
      Map m;
      for (int i = 0; i < 3; ++i)
        m[i * i] = i;
    
      // copy map to vector
    #ifndef OPERATE_ON_KEY
      typedef vector<pair<Map::key_type, Map::mapped_type> > Vector;
      Vector v(m.begin(), m.end());
    #else
      typedef vector<Map::key_type> Vector;
      Vector v;
      v.reserve(m.size());
      BOOST_FOREACH( Map::value_type p, m )
        v.push_back(p.first);
    #endif // OPERATE_ON_KEY
    
      // make PRNG
      ptime now(microsec_clock::local_time());
      ptime midnight(now.date());
      time_duration td = now - midnight;
      mt19937 gen(td.ticks()); // seed the generator with raw number of ticks
      random_number_generator<mt19937, 
        Vector::iterator::difference_type> rng(gen);
    
      // shuffle vector
      //   rng(n) must return a uniformly distributed integer in the range [0, n)
      random_shuffle(v.begin(), v.end(), rng);
    
      // print randomized map elements
      BOOST_FOREACH( Vector::value_type e, v )
    #ifndef OPERATE_ON_KEY
        cout << e.first << ":" << e.second << " ";
    #else
        cout << e << " ";
    #endif // OPERATE_ON_KEY
      cout << endl;
    }
    

答案 7 :(得分:0)

有人试过吗? https://github.com/mabdelazim/Random-Access-Map “用于随机访问映射的C ++模板类。这类似于std :: map,但您可以通过索引随机访问项目,语法为my_map.key(i)和my_map.data(i)”

答案 8 :(得分:0)

std::random_device dev;
std::mt19937_64 rng(dev());

std::uniform_int_distribution<size_t> idDist(0, elements.size() - 1);
auto elementId= elements.begin();
std::advance(elementId, idDist(rng));

现在elementId是随机的:)