为什么拼接整个列表或性病::修饰符Modifiers一个线性范围?(Why is splicing

2019-08-05 14:55发布

剪接的范围从一个列表到另一个可在恒定的时间来完成,在制备为代价size()的复杂度是线性的。

C ++ 11已经改变,在箱子std::list通过要求size()为恒定时间。 这打破了,例如,GCC的实现,请参阅[C ++ 0x中]的std ::目录::大小的复杂性 。

除了范围splice() 是有原因的任何其他原因 size() 不能在早期,C ++ 03符合进行一定时间 std::list 实现?

为什么拼接整个列表或一个线性范围 std::forward_list

splice_after()箱子(1)和(3)。 看到也23.3.4.6修饰符Modifiers操作[forwardlist.ops] N3485标准草案 。 该std::forward_list甚至不执行size()

我知道修饰符Modifiers是一个单向链表,但我不明白为什么人们不能做的范围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 

Answer 1:

在修饰符Modifiers的情况下,你会如何使其应用范围不断splice_after时间? 在源列表,你只有迭代器。 为了从源头上向前链表中删除节点,你会马上需要的节点之前last ,所以你需要线性地查找来源为链表节点。 因此,它为什么被称为之间的距离线性firstlast

使用整个源列表中的版本仍需要立即从来源年底前以搜索节点,以便它可以进行修改,目的拼接后指向的元素。 因此,它也需要在源的大小线性时间。



Answer 2:

该系列接头是唯一的原因, size不会一直在以前的C ++标准的固定时间。 事实上太阳CC编译器选择了把size固定的时间和所有版本的splice线。

拼接整个转发列表是线性的,因为你必须遍历你归并能够将其链接列表的最后一个节点返回到你拼接到列表中。 我想不通,为什么范围拼接是线性的,但。

编辑:作为@Xeo指出,基于范围的版本还需要线性时间,因为last是不在范围包括,它需要从搜索first找到之前的迭代器last



文章来源: Why is splicing an entire list or a range linear for std::forward_list?