C++ 地图中的随机元素

C++ 地图中的随机元素,c++,random,map,C++,Random,Map,从地图中选择随机元素的好方法是什么?C++。我的理解是,映射没有随机访问迭代器。钥匙很长,地图上人烟稀少 如果地图很小或者不经常需要随机值,我喜欢詹姆斯的答案。如果它很大,并且您经常这样做,使速度变得非常重要,那么您可以保留一个单独的键值向量,从中选择一个随机值 map<...> MyMap; iterator item = MyMap.begin(); std::advance( item, random_0_to_n(MyMap.size()) ); map<...>

从地图中选择随机元素的好方法是什么?C++。我的理解是,映射没有随机访问迭代器。钥匙很长,地图上人烟稀少

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

map<...> MyMap;
iterator item = MyMap.begin();
std::advance( item, random_0_to_n(MyMap.size()) );
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 ];

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

也许你应该考虑,虽然注意到它有点太重了。

< P>可以画一个随机键,然后用它找到实际包含的最接近的键。 将贴图复制到向量。 洗牌向量。 在伪代码中,它密切地反映了以下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;
}

继续ryan_关于预构造映射和快速随机查找的主题:我们可以使用迭代器的并行映射来代替向量,这应该会加快随机查找的速度

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())];

如果您的映射是静态的,那么使用向量以键顺序存储键/值对,使用二进制搜索以在logn时间中查找值,使用向量索引以在恒定时间中获取随机对,而不是映射。您可以将向量/二进制搜索包装成具有随机访问功能的地图。

有人尝试过吗? C++模板类用于随机访问的映射。这类似于std::map,但您可以使用语法my_map.keyi和my_map.datai通过索引随机访问项

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是随机的:

为什么需要这样做?使用地图意味着你需要基于一个键的快速查找,随机查找将被启用…我还没有尝试过这个方法,但如果它有效的话,它看起来很完美。我回家后会试试的。这需要包含什么?包含&包含加上你必须滚动你自己的随机0到n…并确保你的随机0到n始终