获取随机元素并将其删除

发布于 2025-01-03 18:37:04 字数 548 浏览 1 评论 0原文

问题:我需要获取容器的随机元素并将其从该容器中删除。容器不需要排序。 我不关心顺序。

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

所以我想出了一个想法,制作一个自定义向量,允许您删除任何元素通过其复杂度为 O(1)+ 的索引。 这个想法是交换最后一个元素和要删除的元素,然后使用 pop_back()。 如果您需要删除最后一个元素 - 只需pop_back()。 向量的顺序不会相同,但您可以获得快速删除方法。

据我了解,与我的解决方案相比,双端队列的索引访问速度更慢,删除复杂度更差,但我不能 100% 确定。

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

Problem: I need to get a random element for a container and also delete it from that container. Container does not need to be sorted. I dont care about the order.

  • Vector can get me random element in O(1) but delete it only in O(N)
  • List deletes element in O(1) but can only get random element in O(N)

So I came up with an idea of making a custom vector that allow you to remove any element by its index with O(1)+ complexity.
The idea is to swap the last element and an element you want to remove and then pop_back().
If you need to remove the last elemtent - just pop_back().
The order of the vector will not be the same but you get a fast remove method.

As i can understand deque have slower access by index and worse removal complexity then my solution but im not 100% sure.

I'm curious are there data structures that have random access and element removal in O(1) or O(logN) by index or mb by value ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心如荒岛 2025-01-10 18:37:04

您已经找到了解决方案,而且看起来非常好。用 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

现在,如果您想返回该对象,并且您可以访问 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;
}

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

You have the solution, and it seems perfectly fine. The idiomatic way to write it in C++ is not to create another class (and please don't inherit from std::vector), but just to write a function:

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();
}

Usage:

remove_at(v, 42);

This offers the same exception guarantee as std::swap<T>.

Now if you want to return the object, and you have access to a C++11 compiler, you can do it the following way. The difficult part is to provide the basic exception guarantee in all cases:

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;
}

Indeed, you don't want the vector to be left in an invalid state if an exception is thrown during a move operation.

跨年 2025-01-10 18:37:04

复杂度为 O(n)

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

如果您想要 O(1) 复杂度,您可以使用列表容器,或者将元素与最后一个元素交换并删除它。 (正如其他人提到的)

With O(n) complexity

vec.erase(vec.begin() + randomIdx);
randomIdx would be between 0 and vec.size()-1

If you want O(1) complexity you could either use the list container for example or swap the element with the last one and delete this instead. ( As mentioned by the others )

自找没趣 2025-01-10 18:37:04

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

每个节点都需要存储每一侧的节点数。由此找到第 n 个元素的时间复杂度为 O(log N)。

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

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

如果标准库“开放”用于 std::set 和 std::map 的树作为在自定义树中使用的公共接口,那实际上会很好。

Yes, there is a solution, a well-balanced binary tree.

One each node you would need to store the number of nodes on each side. From this it is O(log N) to find the nth element.

Removing the nth element is also O(log N) as you have to traverse back up to tree to correct all the counts. Any rebalancing would be O(log N) too at most.

A tree is considered well balanced if no leaf node is 2 nodes deeper than another. Look up AVL trees to get a rabalancing algorithm.

It would actually be good if the standard library "opened" the use of the trees used for std::set and std::map as a public interface for use in custom trees.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文