【问题标题】:C++ Deleting from Vector Efficiency Problem [duplicate]C ++从向量效率问题中删除[重复]
【发布时间】:2020-03-10 19:33:43
【问题描述】:

我有两个版本的完全相同的程序,迷宫生成器,用 Python 和 C++ 编写。我在 Python 中优化后的想法是,如果我用 C++ 重写它,它会更快、更高效。然而,我发现了一件令人惊讶的事情(仔细想想,这并不奇怪)。对于 Python:我的算法从列表中选择一个随机项目,对其进行处理,然后从那里删除它。对于 C++:都一样,但我使用向量而不是列表。在 C++ 中从向量中删除元素比在 Python 中对列表执行相同操作要慢得多,因为当您删除它们时,向量的元素会发生变化。我的问题是:C++ 中最好的数据结构是什么,它可以比向量更快地被索引和删除其项目?

目前,C++ 的删除平均花费的时间是 Python 的 5-6 倍。

【问题讨论】:

  • 为什么要选择随机元素?如果您从矢量的末端开始,按照自己的方式前进,您将获得最快的速度。
  • 指针的 C++ 向量与 python list 完全相同。
  • 那你可以先shuffle向量,然后从向量的末尾开始,往前走
  • 您在测量优化 C++ 构建的时间吗?当有人使用未优化的 C++ 构建时,我看到很多关于 C++ 与其他语言的性能的问题。默认情况下不启用 C++ 中的优化。
  • 请复制/粘贴为文本替换图片。

标签: python c++ data-structures


【解决方案1】:

std::list 是一个链表,与动态数组 std::vector 的线性复杂度相比,具有恒定的任意元素去除复杂度。对于少量元素,由于更好地使用缓存,vector仍然可以更快,但渐近复杂度决定了大量元素的速度。

也就是说,为了从链表中选择一个随机元素进行移除,您需要使用辅助数据结构来实现低于线性的复杂度。

另外,python list 也有删除的线性复杂度,所以不清楚为什么你会认为它更快。

随机删除可能更有效的是由不同大小的段组成的绳索数据结构。但是标准库中并没有用这种数据结构实现的容器。


关于您的特定程序的更多信息,而不是随机或任意删除:似乎更好的算法可能是一种选择:

使用向量。将最后一个有效元素移到“已删除”上,并擦除位于向量末尾的已移动对象。除非有效部分的顺序很重要,否则可以使用此算法。

【讨论】:

  • 但是:在std::vector 中选择一个随机元素是常数时间,在std::list 中选择一个随机元素是线性时间。由于缓存命中与缓存未命中,我希望 std::vector 即使删除也会更快。
  • @MooingDuck 取决于如何选择随机元素。如果使用辅助数据结构,则不必是线性的。
  • 这是真的,如果你已经有一个 list::iterator 的向量可以使用。但是你必须从 that 向量中删除迭代器。你可以有一个随机的 list::iterators 向量来避免向量被移除,但是现在我们从苹果到苹果还有很长的路要走,你可以随机化原始向量来避免这些移除。所以在所有情况下:向量获胜。
  • Strousup 在这里讨论过这个问题:youtube.com/watch?v=YQs6IC-vgmo
  • 总结是,对于随机插入和删除,std::vector 对于所有 N 比 std::list很多
【解决方案2】:

尝试创建一个专门的 vector 类,而不是在您想要删除项目时实际删除它,而是将项目交换到 vector 的末尾到垃圾部分。

这是一个可用于测试性能的代码示例:

#include <vector>
#include <iostream>
using namespace std;

template <typename T>
struct FastDelVec {
    vector<T> data;
    int deleteIndex;

    FastDelVec(int size) {
        data.resize(size);
        deleteIndex = size - 1;
    }

    void Delete(int index) {
        swap(data[index], data[deleteIndex]);
        --deleteIndex;
    }

    size_t size() {
        return deleteIndex + 1;
    }
};

int main() {
    FastDelVec<int> v(100);
    for (int i = 0; i < 100; ++i) {
        v.data[i] = i;
    }

    v.Delete(30);
    v.Delete(5);
    v.Delete(21);

    cout << v.size() << endl;


    system("pause");
    return 0;
}

您还可以尝试其他几种技巧。这会将删除推迟到稍后的时间,因为不断释放堆内存并可能调整 vector 的大小会影响性能

【讨论】:

  • 谢谢,但我已经通过提前改组向量并从头到尾工作找到了解决方案:)
猜你喜欢
  • 2015-02-03
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
  • 1970-01-01
  • 2014-11-23
  • 2020-02-16
  • 2011-11-29
相关资源
最近更新 更多