没有O(1)操作来连接两个forward_lists中的元素?

时间:2011-10-10 14:48:49

标签: c++ complexity-theory c++11

在阅读C ++ 11和N2543的FCD中的forward_list时,我偶然发现splice_after的一个特定重载(略微简化,让cit成为{{ 1}}):

const_iterator

行为是void splice_after(cit pos, forward_list<T>& x, cit first, cit last); 之后pos之间的所有内容都移至(first,last)。因此:

this

描述包括复杂性:

  

复杂性:O(距离(第一,最后))

我可以看到这是因为需要调整 this: 1 2 3 4 5 6 x: 11 12 13 14 15 16 ^pos ^first ^last will become: this: 1 2 13 14 3 4 5 6 x: 11 12 15 16 ^pos ^first ^last PREDECESSOR(last).next = pos.next不允许在O(1)中发生这种情况。

好的,但是没有加入两个单链表在O(1)这个简单数据结构的优势之一?因此我想知道 - forward_list上是否有任何操作在O(1)中拼接/合并/连接任意数量的元素?

当然,算法非常简单。只需要一个操作名称(伪代码):( 通过集成Kerreks答案更新

forward_list

结果略有不同,因为temp_this = pos.next; temp_that = last.next; pos.next = first.next; last.next = temp_this; first.next = temp_that; 未被移动,而是(first,last)

(first,last]

我认为这是一个像前者一样合理的操作,人们可能会这样做 - 特别是如果它有O(1)的好处。

  • 我是否忽略了许多元素上的O(1)操作?
  • 或者我认为 this: 1 2 3 4 5 6 7 x: 11 12 13 14 15 16 17 ^pos ^first ^last will become: this: 1 2 13 14 15 16 3 4 5 6 7 x: 11 12 17 ^pos ^last ^first 作为移动范围可能有用吗?
  • 或者O(1)算法是否有错误?

3 个答案:

答案 0 :(得分:7)

让我先给出一个O(1)拼接算法的修正版本,并举例说明:

temp_this  =   pos.next;
temp_that  =  last.next;

  pos.next = first.next;
 last.next =  temp_this;
first.next =  temp_that;

(理智检查是观察每个变量精确出现两次,一旦设定并且一次得到。)

示例:

    pos.next                           last.next
    v                                  v
1 2 3 4 5 6 7        11 12 13 14 15 16 17 #    
  ^                     ^           ^     ^
  pos                   first       last  end             


becomes:

This:     1 2 13 14 15 16 3 4 5 6 7

That:   11 12             17

现在我们看到,为了拼接到that列表的末尾,我们需要在end() 之前为提供一个迭代器。但是,在恒定时间内不存在这样的迭代器。所以基本上线性成本来自于发现最终迭代器,无论是这样还是另一种:要么在O(n)时间内预先计算它并使用你的算法,要么你只是在线性时间内逐个拼接。

(大概你可以实现你自己的单链表,它会为before_end存储一个额外的迭代器,你必须在相关的操作中不断更新。)

答案 1 :(得分:4)

LWG内部就此问题进行了大量辩论。有关此问题的一些文档,请参阅LWG 897

答案 2 :(得分:1)

当您将end()作为last传递时,您的算法会失败,因为它会尝试使用一个过去的节点并将其重新链接到另一个列表中。允许end()用于除此之外的每个算法都是一个奇怪的例外。

另外我认为first.next = &last;需要first.next = last.next;,否则last将出现在两个列表中。