日志中STL集/映射中的随机元素

时间:2011-07-07 16:23:48

标签: c++ algorithm stl performance

由于C ++ STL set / map被实现为红黑树,因此不仅可以在 O中执行insertdeletefind(log n)时间,还有getMingetMaxgetRandom。据我所知,前两个在begin()end()中有等价物(这是正确的吗?)。最后一个怎么样?我怎么能这样做?

我到目前为止唯一的想法是使用随机参数advance,但这需要线性时间......

编辑:'随机'应指均匀分布

6 个答案:

答案 0 :(得分:8)

begin()等同于getMin操作,但end()会返回超过最大值的迭代器,因此它是rbegin()

至于getRandom:假设你的意思是以均匀概率随机获取任何项目,这可能在AVL树中的O(lg n )时间内,但我不是看看如何在红黑树中有效地做到这一点。您如何知道给定节点左右有多少个子树而不计算 n / 2 = O( n )时间?由于std::setstd::map不能直接访问其基础树,您将如何遍历它?

我看到三种可能的解决方案:

  • 改为使用AVL树;
  • 维护vectormapset中的元素与其平行;
  • 使用带有排序和随机访问视图的Boost::MultiIndex容器。

修改Boost.Intrusive也可以解决问题。

答案 1 :(得分:0)

是,begin和rbegin(not end!)分别是最小和最大键值。

如果您的密钥很简单,例如一个整数,你可以创建一个[min,max)范围内的随机整数(使用),然后获取地图的lower_bound

答案 2 :(得分:0)

如您怀疑begin()end() - 1rbegin()将获得最小值和最大值。我无法看到任何方法在这样的树中统一获取随机元素。但是你有几个选择:

  • 您可以使用advance进行线性时间。
  • 您可以保留一个单独的地图迭代器矢量,以便在所有插入/删除时保持最新。
  • 您可以重新访问容器选择。例如,排序的向量,堆或其他表示会更好吗?

答案 3 :(得分:0)

如果您在集合或地图中均匀分布值,则可以选择最小值和最大值之间的随机值,并使用lower_bound查找与其最接近的值。

如果插入和删除不常见,您可以使用向量代替并根据需要对其进行排序。填充向量并对其进行排序所需的时间与填充集合或映射的时间大致相同;它甚至可能更快,你需要测试它才能确定。那时选择一个随机元素将是微不足道的。

答案 4 :(得分:0)

我认为你可以用STL实际做到这一点,但它有点复杂。

您需要维护地图。每个都带有1..N的密钥(N是元素的数量)。

因此,每次需要使用随机元素时,从1..N生成随机数,然后使用所选键在地图中查找元素。这是你选择的元素。

之后,您需要通过查找最大元素来维护地图的一致性,并使用您刚刚选择的随机数更新其密钥。

由于每个步骤都是log(n)操作,因此总时间为log(n)

答案 5 :(得分:0)

使用现有的STL,可能没有办法。但是通过使用反向索引,可以通过添加std :: map和std :: vector结构来获得O(1)中的随机密钥。

  1. 维护地图m&矢量v。
  2. 当插入新密钥k时,让i = v.length(),然后插入m,并将k推入v,使v [i] = k;
  3. 当删除密钥k时,令i = m [k],在v中查找最后一个元素k2,设置m [k2] = i& v [i] = k2,pop_back v,并从m中删除k;
  4. 得到一个随机密钥,让r = rand()%v.length(),然后随机密钥k = v [r];
  5. 所以基本的想法是拥有所有现有密钥的连续数组。