日志n中STL集合/映射中的随机元素 P>由于C++ STL SET/MAP是作为红黑树实现的,因此,在O(log n)时间内,不仅要执行插入> 、删除> />代码> 查找< />代码,还可以使用 GETMIN、 GETMAX < /C> >、 GeTrand OD//C>。据我所知,前两种方法在begin()和end()中是等效的(正确吗?)。最后一个怎么样?我该怎么做
到目前为止,我唯一的想法是使用带有随机参数的日志n中STL集合/映射中的随机元素 P>由于C++ STL SET/MAP是作为红黑树实现的,因此,在O(log n)时间内,不仅要执行插入> 、删除> />代码> 查找< />代码,还可以使用 GETMIN、 GETMAX < /C> >、 GeTrand OD//C>。据我所知,前两种方法在begin()和end()中是等效的(正确吗?)。最后一个怎么样?我该怎么做,c++,algorithm,stl,performance,C++,Algorithm,Stl,Performance,到目前为止,我唯一的想法是使用带有随机参数的advance,但这需要线性时间 EDIT:“random”应该指均匀分布begin()相当于一个getMin操作,但是end()返回一个超过最大值的迭代器,因此它应该是rbegin() 至于getRandom:假设你的意思是以统一的概率随机获取任何项目,在AVL树中,这可能在O(lg n)时间内实现,但我不知道如何在红黑树中有效地实现。如果不在n/2=O(n)时间内计数,您如何知道给定节点的左侧和右侧有多少子树?既然std::set和std::map
advance
,但这需要线性时间
EDIT:“random”应该指均匀分布begin()
相当于一个getMin
操作,但是end()
返回一个超过最大值的迭代器,因此它应该是rbegin()
至于getRandom
:假设你的意思是以统一的概率随机获取任何项目,在AVL树中,这可能在O(lg n)时间内实现,但我不知道如何在红黑树中有效地实现。如果不在n/2=O(n)时间内计数,您如何知道给定节点的左侧和右侧有多少子树?既然std::set
和std::map
不允许直接访问它们的底层树,您将如何遍历它
我认为有三种可能的解决办法:
- 使用AVL树代替李>
- 保持一个
,其中向量
或映射中的元素
与其平行李>集合
- 使用具有排序和随机访问视图的容器
下限
。如您所怀疑的begin()
和end()-1
或rbegin()
将为您获取最小值和最大值。但我看不到任何方法可以统一获取此类树中的随机元素。不过,您有两个选项:
- 您可以使用advance在线性时间内完成此操作
- 您可以保留一个单独的映射迭代器向量,以便在所有插入/删除操作中保持最新
- 您可以重新选择容器。例如,排序的向量、堆或其他表示形式会更好吗
下限
查找最接近的值
如果插入和删除不频繁,您可以使用向量来代替,并根据需要对其进行排序。填充向量并对其进行排序所需的时间与填充集合或映射所需的时间大致相同;甚至可能更快,您需要对其进行测试以确定是否正确。此时选择随机元素将非常简单。我认为您可以实际上是用STL实现的,但它有点复杂 您需要维护一个映射。每个映射都有一个来自
1..N
(N是元素数)的键
因此,每次需要获取一个随机元素时,从1..N
中生成一个随机数,然后使用所选键在地图中找到该元素。这就是您拾取的元素
之后,您需要通过查找最大的元素来保持贴图的一致性,并使用刚刚拾取的随机数更新其键
由于每个步骤都是一个
log(n)
操作,因此对于现有的STL,总时间是log(n)
,可能没有办法。但是有一种方法可以通过使用反向索引在O(1)中添加std::map和std::vector结构来获取随机键
因此,基本思想是拥有所有现有密钥的连续数组。如果范围不是连续的,则
下限搜索将不会均匀分布。没有人提到任何统计要求:-),但这是一个好的观点。您可以使用rbegin()
获取最大元素。@larsmans:为什么RB树不能跟踪每个子树中的节点/叶数,其中每个操作都会在日志n
时间内更新(无论如何都是必需的)?@dcn这“可能”违反了C++的原则,即不让你为你不需要的东西付费。1和3似乎是公平的选择(如果确实没有纯STL解决方案,我会选择其中一个),2不起作用,因为保持向量需要线性时间,对吗?构建集合或映射需要O(n lg n)时间,因此构建向量不会增加任何渐进复杂性。如果你这样做,请确保将向量中的项存储在集合/映射中,并将其索引到集合/映射中。多索引解决方案将是最优雅的,花费的内存量最少,并将保留引用的局部性。是否有一个容器选择可以提供所有在log n?@ dcn上面的操作中,我不知道任何这样的容器。这就是为什么在决定使用哪个容器时要考虑使用的重要性。你需要决定哪些操作是最常见的,哪些是罕见的来帮助指导这个决定。使用<代码> MAP::LooRixLime你必须已经知道所有包含的项目thoug。h、 我怀疑这是否真的是一个选项。而且std::lower_bound
将执行大量愚蠢的树遍历,大约O(n)个值。@MooingDuck,lower_bound
不需要精确匹配,因此您可以选择一个随机值并在不知道精确值的情况下在地图中找到最近的项。当然,您会使用内置的