获取随机元素并将其删除

时间:2012-02-09 21:03:56

标签: c++ performance data-structures vector big-o

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

  • Vector可以在O(1)中获取随机元素,但只能在O(N)
  • 中将其删除
  • 列表会删除O(1)中的元素,但只能在O(N)
  • 中获取随机元素

所以我提出了一个创建自定义向量的想法,允许您通过其O(1)+复杂度的索引删除任何元素。 想法是交换最后一个元素和要删除的元素,然后pop_back()。 如果您需要删除最后一个元素 - 只需pop_back()。 向量的顺序不一样,但是你得到一个快速删除方法。

我可以理解deque的索引访问速度较慢,删除复杂性较差,然后我的解决方案却不是100%肯定。

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

3 个答案:

答案 0 :(得分:14)

你有解决方案,看起来非常好。用C ++编写它的惯用方法不是创建另一个类(而 don't inherit from 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;
}

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

答案 1 :(得分:0)

O(n)复杂度

vec.erase(vec.begin()+ randomIdx); randomIdx介于0和vec.size() - 1

之间

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

答案 2 :(得分:0)

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

每个节点需要存储每侧的节点数。从这里找到第n个元素是O(log N)。

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

如果没有叶节点比另一个节点更深2个节点,则认为树很平衡。查找AVL树以获得一个平衡算法。

如果标准库“打开”使用用于std :: set和std :: map的树作为用于自定义树的公共接口,那将是很好的。