O(1)在无序向量中删除

时间:2015-06-29 12:27:41

标签: c++ vector stl

在C ++程序中,我有一组普通旧数据,我需要能够有效地使用它:

  • 添加元素。
  • 迭代整个系列。
  • 删除其中一些元素(请参阅下面的更新).iteration,见下文。

我不必使用集合或地图类型,因为没有外部要求:

  • 索引到它
  • 维持订购。
  • 有效地找到元素或测试它们在集合中。

如果我必须在C中从头开始编写它,我将使用指数增长的动态数组,删除操作会将最后一个元素移动到释放的插槽中。那样删除就是O(1)。

如果我想使用C ++标准容器,似乎我可以(a)使用std::vector但是手动编写删除操作或(b)使用std::list。我有一个温和但明确的不喜欢链表。

这两种解决方案对我来说都是可以接受的,但我真的更喜欢两种方式:使用矢量但只使用标准操作。有没有办法做到这一点。

更新

下面的评论表明我不是在寻找一般的删除操作。我的问题要求我经常迭代集合,并且在每次传递时我都希望发现必须删除一些元素。

无论删除次数多少,我都可以在O(n)时间完成整个操作。但这显然是一个定制的操作,我应该知道我需要编写自己的循环。令人惊讶的是remove_if 几乎解决了我的问题。如果我在迭代过程中唯一需要做的就是识别过时的元素,那么remove_if就可以完成这项工作,但我也需要做其他处理。

6 个答案:

答案 0 :(得分:2)

实际上,这已经在标准库中了:

std::remove_if还允许您在一次迭代中删除一大堆元素。

并且,可能最重要的是,由于您的数据是连续存储的,迭代将最快 - >没有缓存未命中。

答案 1 :(得分:1)

这是一个擦除功能,可以从容器的末端移动元素:

template <typename Vector>
void unordered_erase(Vector& v, typename Vector::iterator it) {
    *it = std::move(v.back());    
    v.pop_back();
}

Demo

答案 2 :(得分:0)

您可以在向量中为delete函数编写一个包装器,其中将最后一个元素复制到要删除的位置,然后在最后一个元素处调用标准erase函数。擦除最后一个元素将是O(1)。

它会是这样的:

void delete(vector<int> data, int position)
{
  data[position] = data[data.size() - 1];
  data.erase(data.begin() + data.size() - 1);
  return;
}

我假设要删除一个数字,您将给出删除它的位置。如果是其他内容,请注明。

答案 3 :(得分:0)

这取决于集合的大小,每个元素的大小等。根据bog标准向量的大小和性能,您可以创建一个新的向量,只执行一次旧的向量并仅按下项目不配。那是O(N)。

标准库有std :: copy_if。例如,以下内容从第一个向量中删除所有值2。剩下的就是第二个。

#include <vector>
#include <algorithm>
#include <iterator>

int main(void)
{
    std::vector<int> v1 = { 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 9, 2, 3, 2, 2};
    std::vector<int> v2;

    std::copy_if(v1.begin(), v1.end(), std::back_inserter(v2), [](int value) { 
        return value != 2;
    });

}

在我的性能测试中(有50,000,000个随机数),这比remove_if方法略慢:

第32版:copy_if(1412),remove_if(1120)

第64版:copy_if(1420),remove_if(1141)

答案 4 :(得分:0)

解决整个问题的可能方案:

std::vector<MyClass> v;
// ...fill v...
v.erase(std::partition(v.begin(), v.end(), [](MyClass& element) -> bool {
    // ...process element and return false if element should be deleted.
}), v.end());

我知道它已经很晚了,但有人可能仍觉得它很有用。

答案 5 :(得分:0)

这是remove_if的替代方法,可以在不维持订单的情况下进行交换。

/// faster remove_if, but it doesn't keep order.
/// Swaps matched items to back; returns iterator to start of matched items
template <typename C, typename F>
inline typename C::iterator swapBackIf(C & v, F comp) {
  auto iter = v.begin();
  auto rear = v.end();
  for (iter; iter < rear; ++iter) {
    auto const& ele = *iter;
    if (comp(ele)) {
      std::iter_swap(iter, --rear);
    }
  }
  return rear;
}