获取随机元素并将其移除
Get random element and remove it
问题:我需要为容器获取一个随机元素,并将其从该容器中删除。容器不需要排序我不在乎订单
- Vector可以在
O(1)
中获取我的随机元素,但只能在O(N)
中删除它 - List删除
O(1)
中的元素,但只能获得O(N)
中的随机元素
因此,我想出了一个想法,制作一个自定义向量,允许您通过O(1)+
复杂度的索引来删除任何元素。其想法是交换最后一个元素和要删除的元素,然后再交换pop_back()
。如果您需要删除最后一个元素-只需pop_back()
。向量的顺序将不相同,但您可以获得快速移除方法。
正如我所理解的,与我的解决方案相比,deque的索引访问速度较慢,删除复杂性较差,但我不能100%确定。
我很好奇O(1)
或O(logN)
中是否存在按索引或按值进行随机访问和元素移除的数据结构?
您有了解决方案,它看起来非常好。用C++编写它的惯用方法不是创建另一个类(请不要从std::vector
继承),而是编写一个函数:
template <typename T>
void remove_at(std::vector<T>& v, typename std::vector<T>::size_type n)
{
std::swap(v[n], v.back());
v.pop_back();
}
用法:
remove_at(v, 42);
这提供了与std::swap<T>
相同的异常保证。
现在,如果您想返回对象,并且您可以访问C++11编译器,您可以按照以下方式进行。困难的部分是在所有情况下提供基本的例外保证:
template <typename T>
T remove_at(std::vector<T>&v, typename std::vector<T>::size_type n)
{
T ans = std::move_if_noexcept(v[n]);
v[n] = std::move_if_noexcept(v.back());
v.pop_back();
return ans;
}
事实上,如果在移动操作期间引发异常,您不希望向量处于无效状态。
具有O(n)复杂性
vec.erase(vec.begin()+randomIdx);randomIdx将介于0和vec.size()-1 之间
如果你想要O(1)的复杂性,你可以使用列表容器,或者用最后一个交换元素并删除它。(如其他人所述)
是的,有一个解决方案,一个平衡良好的二进制树。
每个节点一个,您需要存储每一侧的节点数。从中找到第N个元素是O(log N)。
删除第N个元素也是O(logN),因为您必须遍历回树以更正所有计数。任何再平衡至多也是O(logN)。
如果没有叶节点比另一个叶节点深2个节点,则认为树是平衡的。查找AVL树以获得Rabalance算法。
如果标准库"开放"使用std::set和std::map所使用的树,作为在自定义树中使用的公共接口,那就太好了。
- 从C++数组中选择一个随机元素
- 用随机元素填充矢量
- 将集合的随机元素添加到列表中,然后将其从原始集合中移除
- 从长(且合理)稀疏向量中选择随机元素的最有效方法是什么?
- 更快地访问 C++ 数组中的随机元素
- 从容器中获取随机元素,该容器在恒定时间内没有严格的元素顺序
- 选择C++地图中随机元素的百分比
- C++将字符从静态数组复制到动态数组会添加一堆随机元素
- 如何有效地从std::集中选择随机元素
- 如何在数组中拾取一些随机元素
- 为多映射中的特定键选择随机元素
- 如何从向量中删除随机元素而不重复它们并保持元素顺序?C++
- 如何在 c++ 中从枚举返回随机元素
- 如何从填充.txt文件名的向量中选取随机元素C++
- 在unordered_map中选择随机元素
- 算法-统一随机元素链表
- 从具有印地语字符的数组中生成随机元素
- 获取随机元素并将其移除
- 这是从容器中获取随机元素的OK范围的方法吗
- 如何在小于O(n)的时间内选择std::集合中的一个随机元素