C++ std::forward_list和std::forward_list::push_back

C++ std::forward_list和std::forward_list::push_back,c++,c++11,std,forward-list,C++,C++11,Std,Forward List,我想用 因为: 转发列表是一个支持快速插入和删除的容器 来自容器任何位置的元素 但是没有*std::forward\u list::push\u back*实现 是否有一种高性能的方法来添加对一个或无理由的支持?std::forward\u list支持快速插入和删除,但不支持遍历到底。要实现.push_back,您首先需要到达列表的末尾,它是O(N)并且一点也不快,这可能就是它没有实现的原因 您可以通过在开始之前增加N次来找到最后一个元素的迭代器 auto before_end = slis

我想用

因为:

转发列表是一个支持快速插入和删除的容器 来自容器任何位置的元素

但是没有*std::forward\u list::push\u back*实现


是否有一种高性能的方法来添加对一个或无理由的支持?

std::forward\u list
支持快速插入和删除,但不支持遍历到底。要实现
.push_back
,您首先需要到达列表的末尾,它是O(N)并且一点也不快,这可能就是它没有实现的原因

您可以通过在开始之前增加
N次来找到最后一个元素的迭代器

auto before_end = slist.before_begin();
for (auto& _ : slist)
  ++ before_end;
然后使用
.insert_在
之后或
之后。在
之后放置_插入元素:

slist.insert_after(before_end, 1234);

没有
push_back
,因为列表不跟踪列表的后面,只跟踪列表的前面

您可以围绕列表编写一个包装器,该包装器将迭代器保存到最后一个元素,并根据列表是否为空,使用
insert\u after
push\u front
实现
push\u back
。如果要支持更复杂的操作(例如,
sort
splice\u after
),这将变得相当复杂

或者,如果您不需要
向后推
来加快速度,那么可以直接在线性时间内完成


除非内存非常紧张,否则最好的解决方案是使用
list
。这与
前推列表
具有相同的性能特征,并且是双向的,支持
后推
以及
前推
;成本是每个元素增加一个指针。

std::forward\u 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);
转发列表a;
auto it=a.在开始之前();
对于(int i=0;i<10;++i)
it=a.在(it,i)之后插入_;

我反对
std::forward\u list
就像我反对
std::list
在几乎所有情况下一样。就我个人而言,我从未在代码中发现链表是最好的数据结构

<>在C++中,默认的数据收集应该是代码> STD::vector < /代码>。如果这是您真正需要的,它将为您提供高效的
后推
。从技术上讲,如果只查看一个操作的抽象big-O复杂性度量,就无法从中间进行有效的删除和插入。然而,在现实世界中,
std::vector
即使在中间插入和删除,仍然会赢得

例如,Bjarne Stroustrup创建了100000个元素的测试
std::list
vs.
std::vector
。他将搜索每个元素并删除它。然后他会找到一个插入点并插入到中间。他本可以在
std::vector
上使用二进制搜索,但没有使比较“更公平”

结果显示,
std::vector
,即使在这种情况下,
std::list
被认为是强大的,也是一个强大的赢家。简单地遍历
std::list
需要更长的时间,因为所有对象在内存中的距离都很大
std::list
对缓存不友好,这可能是现代处理器最重要的一点

注意,这里的第二个链接给出了一些可能需要使用
std::list
的情况,例如当元素的大小较大时。然而,我一直处于这样一种情况:我有许多元素按特定顺序排列,需要删除一些

这些元素比任何内置类型都大,但并不庞大(在32位计算机上,每个元素可能有20-30字节)。元素的数量足够大,所以我的整个数据结构只有几百个MiB。数据收集是一组基于当前已知信息理论上可能有效的值。该算法对所有元素进行迭代,并根据新信息删除不再有效的元素,每次遍历可能会删除大约80%的剩余元素


我的第一个实现是一种简单的
std::vector
方法,在遍历时删除了无效元素。这对小测试数据集有效,但当我尝试做真实的事情时,它太慢了,没有用处。我切换到一个
std::list
作为容器,但使用了相同的算法,我看到了显著的性能改进。然而,它仍然太慢,无法发挥作用。成功的改变是切换回一个
std::vector
,但我没有删除不好的元素,而是创建了一个新的
std::vector
,我发现好的元素都被放入该
std::vector
,然后在函数结束时,我会简单地丢弃旧的
std::vector
并使用新的,这给了我比
std::list
更快的速度,就像
std::list
给了我比原来的
std::vector
实现更快的速度一样,这足够快,非常有用。

不幸的是,我不能添加注释(信誉度低),但我只想指出,forward_list&list的优点之一是插入-删除操作不会使迭代器无效。我有一个应用程序,其中元素集合在迭代和处理单个元素时不断增长。没有迭代器失效允许我执行段扫描(列表的开始作为段的开始,最后一段的开始作为结束)。

当然,可以通过存储指向其末端的额外迭代器来修改
前向列表。这样,
push_back
就可以在O(1)中完成