C++ 没有O(1)操作来连接两个前向列表中的元素?

C++ 没有O(1)操作来连接两个前向列表中的元素?,c++,complexity-theory,c++11,C++,Complexity Theory,C++11,在阅读C++11的FCD中的forward_list时,我无意中发现了splice_在之后的一个特定重载(稍微简化,让cit成为const_迭代器): 描述包括复杂性: 复杂度:O(距离(第一个,最后一个)) 我可以看出这是因为需要调整前置(last).next=pos.next,而转发列表不允许在O(1)中发生这种情况 好的,但是在O(1)中连接两个单链表不是这个简单数据结构的优点之一吗?因此我想知道--在forward\u list上是否没有拼接/合并/连接O(1)中任意数量元素的操作? 当

在阅读C++11的FCD中的
forward_list
时,我无意中发现了
splice_在
之后的一个特定重载(稍微简化,让
cit
成为
const_迭代器
):

描述包括复杂性:

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

我可以看出这是因为需要调整
前置(last).next=pos.next
,而
转发列表不允许在O(1)中发生这种情况

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

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

结果有点不同,因为移动的不是
(first,last)
,而是
(first,last)

  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)的好处的话

  • 我是否忽略了在许多元素上都是O(1)的操作?
  • 或者我的假设是错误的,
    (第一个,最后一个)
    可能作为移动范围有用吗?
  • 或者O(1)算法中有错误吗?

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


另外,我认为
first.next=&last;
必须是
first.next=last.next;
,否则
last
将在两个列表中。

首先让我给出一个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首末端
变成:
这是:123141634567
那是11 12 17
现在我们看到,为了拼接到
列表的末尾,我们需要在
end()
之前提供一个迭代器。但是,在固定时间内不存在这样的迭代器。因此,基本上线性成本来自于发现最终的迭代器,不管怎样:要么在O(n)中预计算它时间和使用你的算法,或者你只是一个接一个地拼接,也是在线性时间


(大概您可以实现自己的单链表,该单链表将在_end
之前为
存储一个额外的迭代器,您必须在相关操作期间不断更新该迭代器。)

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

您的解决方案的详细信息有点离题,但问题是好的。+1因为没有(第一个、最后一个)被移动,而是(第一个,最后一个)。这正是问题所在,所有标准算法都是基于该假设工作的,有这样一个例外会让人感到困惑。@Plasmah并不像所有其他算法一样,已经违反了标准假设?如果在结束之前有一个
迭代器,那么它确实可以完成。@ChristianRau:确实。看看这有多混乱?如果有另一个不同的版本,会有多混乱。标准容器是为了方便使用而创建的,而不是为了最终的性能。我们确实有“结束之前的一个”。这是最后一个。下一个是不是?我想我还不够清楚。问题是,你提出的算法只有在能够明智地获得所需序列的最后一个元素的迭代器时才有用,但通常在恒定时间内这是不可能的。因此,整个算法不被认为是有用的。换句话说,你是怎么得到的首先是
last
迭代器?@towi:他指的是
last
之前的迭代器。是的。从其他答案中得到了。@Dani:不,不是真的。我的意思是,一般来说,没有一个常数时间操作可以获得一个好的结束迭代器。仔细想想,人们可能会提供这种算法作为情况的替代方法您已经通过其他方法获得迭代器对的情况。这听起来像是在情境上有用的事情。
temp_this  =   pos.next;
temp_that  =  last.next;
  pos.next = first.next;
 last.next =  temp_this;
first.next =  temp_that;
  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   
temp_this  =   pos.next;
temp_that  =  last.next;

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