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