【问题标题】:Splicing full list in constant time在恒定时间内拼接完整列表
【发布时间】:2015-10-14 12:46:30
【问题描述】:

我试图在恒定时间内拼接(连接)两个完整的 std::lists。通过阅读文档和其他问题 (How to do range splice in constant time with std::forward_list?),我有两个澄清问题:

  1. 是否可以在恒定时间内拼接两个 std::list 并保留每个列表的完整列表?
  2. 我的理解是,这个功能可以通过创建我自己的列表数据结构来实现 - 并使用类似于以下的函数(伪代码):

    List joinLists(List list1, List list2) {
    
      list1->tail = list2->head;
    
      list1->tail = list2->tail;
    
      return list1;
    
    }
    

这是真的吗?如果没有,如果有人可以帮助我了解这里发生了什么,我将不胜感激。我觉得我错过了什么..

我正在使用的代码在这里:

 auto simple_sorter = [this, numCores](std::vector<std::vector<std::list<unsigned int>>>& buckets_small_, std::vector<std::list<unsigned int>>& buckets_large_, std::vector<bool>& finished_, unsigned int range_low, unsigned int range_high, int thread_number)
{
    //.. irrelevant

    //Combine small buckets into single large bucket per thread
    for(unsigned int i = 0; i < numCores; ++i) {
        std::list<unsigned int> list1 = buckets_large_[thread_number];
        list1.splice(list1.end(), buckets_small_[i][thread_number]);

    //...
};

(注意:Boost/其他库不是一个选项)

【问题讨论】:

  • splice 是一种破坏性操作 - 列表“物理地”连接在一起。您不能在恒定时间内以非破坏性方式连接列表。

标签: c++ list stdlist


【解决方案1】:
  1. 是的,std::list::splice 以这种方式工作(复杂度为 O(1))(1)

没有元素被复制或移动,只有列表节点的内部指针被重新指向。

  1. 假设一个抽象的单链表,你会这样做

    list1->back->next = list2->front;
    list1->size += list2->size;
    

    对于双链表,你也可以这样做

    list2->front->prev = list1->back;
    

    如果你想在list1nth元素之后插入list2的元素,你需要找到那个元素,然后做同样的事情

    element->next = list2->front;        
    //for a double-linked list:
    list2->front->prev = element;
    

    在任何一种情况下,都不会复制任何数据,您只需在这里和那里交换指针。

【讨论】:

  • 我就是这么想的。但是,我包含的代码是以线性时间运行的。从 std::list::splice 的文档来看,对于以下任何一种情况,它都以恒定时间运行: void splice (const_iterator position, list& x); void splice (const_iterator position, list&& x);我在上面的代码中遗漏了什么吗?我正在考虑建立我自己的列表来获得这个功能
  • @qwerty3,复制列表是 O(n),所以我认为是这条线运行缓慢而不是拼接:std::list&lt;unsigned int&gt; list1 = buckets_large_[thread_number];
  • 我错过了!!我是否正确:list1.splice(buckets_large_[thread_number].end(), buckets_small_[i][thread_number]);不会调用复制构造函数?感谢您的帮助。
  • @qwerty3,是的,这样应该没问题
【解决方案2】:

(以下为伪代码)

拼接是交织的:

new_list = list1[0], list2[0], list1[1], list2[1], ...

连接是将两个列表连接在一起:

new_list = list1, list2

(以下是未经测试的(略少伪)代码)

拼接:

List splice(List list1, List list2){
  List<stuff> things ;
  List<stuff> * small_list = list1.size() > list2.size() ? &list2 : &list1 ;
  List<stuff> * big_list = list1.size() > list2.size() ? &list1 : &list2 ;
  for(int i = 0 ; i < small_list->size() ; i++ ){
    things << list1[i] << list2[i] ;
  }
  for(int i = small_list->size() ; i < big_list->size()){
    things << (*big_list)[i] ;
  }
  return things ;
}

非常确定您必须在返回值和参数中定义您的列表包含的内容(或使用模板进行多态性,我现在不知道)

免责声明:我被 ruby​​ 宠坏了,忘记了这是否是有效的 c++...

【讨论】:

  • 你搞错了 std::list::splice 的作用。
  • 是的,我在写它的时候。这个函数的名字不好。
  • 这是破坏性地将元素插入到链表中的标准名称。我想不出任何将交错称为“拼接”的语言。
  • 英文。这是我的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-13
  • 1970-01-01
  • 2013-10-20
  • 2018-10-10
  • 1970-01-01
相关资源
最近更新 更多