关于c ++:获取随机元素并将其删除

Get random element and remove it

问题:我需要为一个容器获取一个随机元素,并从该容器中删除它。容器不需要排序。我不在乎订单。

  • 矢量可以在O(1)中得到随机元素,但只能在O(N)中删除。
  • list删除O(1)中的元素,但只能得到O(N)中的随机元素。

因此,我想出了一个主意,制作一个定制的向量,允许您通过它的索引删除具有O(1)+复杂性的任何元素。其思想是交换最后一个元素和要删除的元素,然后交换pop_back()。如果您需要删除最后一个元素-仅限于pop_back()。向量的顺序将不相同,但您会得到一个快速删除方法。

据我所知,deque的索引访问速度较慢,删除复杂性比我的解决方案更差,但我不能百分之百确定。

我很好奇,在O(1)O(logN)中是否存在随机访问和元素删除的数据结构(按索引)或mb(按值)?


你有解决办法,看起来很好。在C++中编写它的惯用方法不是创建另一个类(并且请不要从EDCOX1(0)中继承),而是写一个函数:

1
2
3
4
5
6
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();
}

用途:

1
remove_at(v, 42);

这提供了与std::swap相同的例外担保。

现在,如果你想返回这个对象,并且你可以访问C++ 11编译器,你可以这样做。困难的部分是在所有情况下提供基本例外担保:

1
2
3
4
5
6
7
8
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;
}

实际上,如果在移动操作期间引发异常,则不希望向量处于无效状态。


是的,有一个解决方案,一个平衡良好的二叉树。

每侧需要一个节点来存储节点的数量。从这里,找到第n个元素是O(logn)。

删除第n个元素也是O(logn),因为您必须遍历回树以更正所有计数。任何再平衡最多也是O(log n)。

如果没有叶节点比另一个节点深2个节点,则认为树平衡良好。查找AVL树,得到一个均衡算法。

如果标准库"打开"使用std::set和std::map所用的树作为公共接口,以在自定义树中使用,实际上是很好的。


具有O(N)复杂性

vec.erase(vec.begin()+随机化x);RandomDx将介于0和vec.size()-1之间

如果您想要O(1)复杂性,您可以使用列表容器,或者用最后一个容器交换元素,然后删除它。(如其他人所述)