问题:我需要为容器获取一个随机元素,并将其从该容器中删除。容器不需要排序。 我不在乎订单。
O(1)
中获取随机元素,但只能在O(N)
O(1)
中的元素,但只能在O(N)
所以我提出了一个创建自定义向量的想法,允许您通过其O(1)+
复杂度的索引删除任何元素。
想法是交换最后一个元素和要删除的元素,然后pop_back()
。
如果您需要删除最后一个元素 - 只需pop_back()
。
向量的顺序不一样,但是你得到一个快速删除方法。
我可以理解deque的索引访问速度较慢,删除复杂性较差,然后我的解决方案却不是100%肯定。
我很好奇数据结构是否在O(1)
或O(logN)
中按索引或mb按值删除了随机访问和元素?
答案 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的树作为用于自定义树的公共接口,那将是很好的。