由于:
转发列表是一个支持快速插入和删除的容器 来自容器的任何地方的元素
但是没有* std :: forward_list :: push_back *实现。
是否有一种高性能的方式来增加对单一或无理由的支持?
答案 0 :(得分:26)
我建议反对std::forward_list
,就像我在几乎所有情况下都建议反对std::list
一样。就个人而言,我从未在我的代码中发现链接列表是最佳数据结构的情况。
在C ++中,您的默认首选数据集应为std::vector
。它为您提供高效push_back
,如果这是您真正需要的。如果您只查看该操作的抽象大O复杂度测量,从技术上讲,它不能从中间有效地删除和插入。然而,在现实世界中,std::vector
仍然赢得,即使在中间插入和删除。
例如,Bjarne Stroustrup创建了一个100,000元素std::list
与std::vector
的测试。他会搜索每个元素并删除它。然后他会找到一个插入点并插入中间。他可以在std::vector
上使用二分搜索,但不会使比较“更公平”。
结果显示std::vector
获胜,即使在std::list
强大的情况下也是如此。简单地遍历std::list
需要更长的时间,因为所有对象在内存中的距离是多远。 std::list
不是缓存友好的,这可能是现代处理器最重要的事情。
The complete talk by Bjarne Stroustrup
Thorough explanation of the effects, with benchmarks at multiple sizes
请注意,此处的第二个链接提供了一些您可能想要使用std::list
的情况,例如元素的大小很大时。但是,我一直处于这样一种情况:我按特定顺序拥有许多元素,需要删除一些元素。
这些元素比任何内置类型都要大,但不是很大,在32位计算机上可能各占20-30个字节。元素的数量足够大,因此我的整个数据结构只有几百MiB。数据收集是一组基于当前已知信息理论上可以有效的值。该算法迭代所有元素并删除了基于新信息不再有效的元素,每次传递可能会删除大约80%的剩余元素。
我的第一个实现是一个简单的std::vector
方法,我在遍历时删除了无效元素。这适用于小型测试数据集,但是当我尝试做真实的事情时,它太慢而无法使用。我切换到std::list
作为容器,但使用相同的算法,我看到了显着的性能改进。但是,它仍然太慢而无法使用。获胜的更改是切换回std::vector
,但是我没有删除不合适的元素,而是创建了一个新的std::vector
,并且我发现任何好的元素都放入了std::vector
std::vector
。 1}},然后在函数结束时我会简单地丢弃旧的std::list
并使用新的std::list
,这给了我std::vector
与{{1}}一样快的速度{1}}让我完成了我原来的{{1}}实施工具,这个速度非常快,非常有用。
答案 1 :(得分:17)
std::forward_list
支持快速插入和删除,但不支持遍历。要实现.push_back
,您首先需要到达列表的末尾,即O(N)并且根本不快,这可能是它未实现的原因。
您可以通过递增.before_begin
N次
auto before_end = slist.before_begin();
for (auto& _ : slist)
++ before_end;
然后使用.insert_after
或.emplace_after
插入元素:
slist.insert_after(before_end, 1234);
答案 2 :(得分:6)
std :: forward_list的要点是std :: list的超精简版本,因此它不会将迭代器存储到最后一个元素。如果你需要,你必须自己维护它,如下:
forward_list<int> a;
auto it = a.before_begin();
for(int i = 0; i < 10; ++i)
it = a.insert_after(it, i);
答案 3 :(得分:5)
没有push_back
因为列表没有跟踪列表的后面,只跟踪前面。
您可以在列表周围编写一个包装器来维护最后一个元素的迭代器,并使用push_back
或insert_after
实现push_front
,具体取决于列表是否为空。如果您想支持更复杂的操作(例如sort
和splice_after
),这将变得相当复杂。
或者,如果您不需要push_back
快速,则可以直接在线性时间内完成。
除非内存非常严格,否则最佳解决方案是使用list
。这与forward_list
具有相同的性能特征,并且是双向的,支持push_back
以及push_front
;成本是每个元素的额外指针。
答案 4 :(得分:0)
不幸的是,我无法添加评论(声望很低),但我只是想提一下forward_list&amp; list的优点是insert-delete操作不会使迭代器失效。我有一个应用程序,在迭代和处理单个元素的同时,元素集合正在增长。没有迭代器失效允许我实现段扫描(列表的开头作为段的开始,最后一段的开始作为结束)。