将一个范围从一个列表拼接到另一个列表可以在恒定时间内完成,但代价是size()
的复杂度是线性的。
C ++ 11在std::list
的情况下通过要求size()
为常量时间而改变了。例如,这打破了gcc的实现,请参阅[C++0x] std::list::size complexity。
除了范围splice()
之外,还有其他原因 size()
无法在之前的C ++ 03符合< / strong> std::list
实施?
为什么拼接整个列表或线性范围为 std::forward_list
?
见splice_after()
,案例(1)和(3)。另见standard draft N3485中的23.3.4.6 forward_list操作[forwardlist.ops]。 std::forward_list
甚至没有实现size()
。
我知道forward_list是一个单链表,但我不明白为什么人们不能在恒定时间内完成范围splice_after()
。我可能在这里遗漏了一些小事......
编辑:好的,至少部分是我的误解,我预计4 不会保留在源列表中。代码:
#include <algorithm>
#include <iostream>
#include <forward_list>
using namespace std;
void dump_list(const forward_list<char>& l) {
for(char c : l)
cout << c << ' ';
cout << '\n';
}
int main()
{
forward_list<char> trg = {'a','b','c'};
forward_list<char> src = {'1','2','3','4'};
auto first = src.begin();
auto last = find(src.begin(), src.end(), '4');
cout << "first = " << *first << ", last = " << *last << "\n\n";
trg.splice_after(trg.begin(), src, first, last);
cout << "Target after splice:\n";
dump_list(trg);
cout << "Source after splice:\n";
dump_list(src);
cout << endl;
return 0;
}
输出:
first = 1, last = 4
Target after splice:
a 2 3 b c
Source after splice:
1 4
答案 0 :(得分:2)
在forward_list的情况下,你如何使范围splice_after恒定时间?在源列表中,您只有迭代器。要从源转发链接列表中删除节点,您需要在last
之前的节点,因此您需要线性搜索该链接列表节点的源。因此,为什么它在first
和last
使用整个源列表的版本仍然需要在源结束之前立即搜索节点,以便可以修改它以指向目标中拼接之后的元素。因此,它还需要源的大小的线性时间。
答案 1 :(得分:1)
范围拼接是size
在以前的C ++标准中不是常数时间的唯一原因。实际上,Sun CC编译器选择使size
为splice
的常量时间和所有版本的last
线性。
拼接整个前向列表是线性的,因为你必须遍历你正在合并的列表,以便能够将它的最后一个节点链接回你正在拼接的列表中。我无法弄清楚为什么范围拼接是线性的。
编辑:正如@Xeo指出的那样,基于范围的版本也需要线性时间,因为first
未包含在范围内,需要从last
搜索以找到迭代器之前 {{1}}。