【问题标题】:Behavior of std::map iterators and insertionsstd::map 迭代器和插入的行为
【发布时间】:2017-08-25 12:55:50
【问题描述】:

作为一个简单的开始

Map<key,val> map1=//filled up in some way;
Map<key,val> map2;
map2.insert(map1.begin(),map1.end());

我们知道map::insert 是 O(log(n)),没有提供任何提示。这是否意味着上述运行在 O(nlog(n)) 中,或者它是否使用 map1 已经排序并简单地插入到正确位置(递增当前迭代器)的事实?因为 map1 已经排序,我们应该能够在线性时间内做到这一点。怎么样

std::copy(map1.begin(),map1.end(),map2.end());

它是每次在 O(log(n)) 中插入,还是在 O(1) 中复制到通过递增迭代器标记的尊重位置?

也许是一个更具说明性的例子

template<class InIter, class OutIter, class ResIter>
ResIter foo(InIter first, OutIter last, ResIter res){
   while(first!=last){
      res=*first;
      ++first;
      ++res;
   }
return res;
}

当我们处理映射迭代器时,这是否运行在 O(n) 或 O(nlog(n)) 中?插入是 O(log(n)),还是 O(1),因为我们指定了位置,即*res=*first

为清楚起见进行编辑:

*res=*first

表现得像

map2.insert(res,*first)

意思是,插入到map2中,使用指向正确位置的迭代器res作为提示,使其成为O(1),还是执行常规的O(log(n))插入?

【问题讨论】:

  • 好问题。请注意,如果您使用实际的复制构造函数,您可能会得到一个有效的副本。另一种选择是在循环中插入,使用end() 作为插入提示,如果您按顺序阅读源映射,这始终是正确的。 (您可以使用 copy 和插入迭代器来做到这一点。)
  • std::copy(map1.begin(),map1.end(),map2.end()); 如果map1 不为空,则具有未定义的行为,因为map2.end() 不可取消引用。
  • 有没有办法在通过迭代器插入时使用提示,例如 *res=*first ?我问是因为这是一个玩具示例,在真实示例中,它不是要复制整个地图。关于您的评论,我应该将其更改为 map2.begin()?
  • 将有序数据插入平衡二叉树实际上是更糟糕的情况,因为每次插入后都必须重新平衡树。如果树没有重新平衡,所有节点都将沿着树的一个分支创建。
  • 但是 map1 的内容已经排序,这就是为什么我声称我们应该能够在线性时间内做到这一点。也许我误解了你。

标签: c++ iterator time-complexity stdmap


【解决方案1】:

快速阅读标准后,对void insert(InputIterator first, InputIterator last); 的复杂性没有要求。因此,允许惰性实现具有 O(n log(n)) 复杂度,即使 map1 为空,由于以下原因,它很可能是线性的。

因为如果输入范围已排序,标准确实要求构造函数具有线性复杂度,因此要求为 O(n):

Map<key,val> map1=//filled up in some way;
Map<key,val> map2(map1.begin(),map1.end()); // complexity in O(n)

对于您问题的第二部分,由于您想提示应该在哪里插入元素,正确的方法是:

template<class InIter, class OutIter, class ResIter>
ResIter foo(InIter first, OutIter last, ResIter res){
   while(first!=last){
      emplace_hint(res, *first);
      ++first;
      ++res;
   }
return res;
}

不幸的是,标准对emplaceemplace_hint 的复杂性没有任何要求。

【讨论】:

  • 上半年,我不需要副本,我做了一个(可能失败的)人为的例子作为我问题的基础。对于您的第二部分,请参阅我的编辑以清楚了解 -> 我理解正确,这意味着 *res=*first 的行为不像 map2.insert(res,*first),但您的 emplace_hint 可以吗?
  • 标准明确表示map2.insert(res, *first) 等同于return emplace_hint(res, std::forward(*first))
  • 我在标准中找不到任何参考,但我认为 *res = *first; 也等同于 map2.insert(res, *first);
  • 他们将很多东西移到了 23.2(容器要求)。 insert(InputIterator first, InputIterator last); 的复杂度指定为 a.insert(i, j) N log(a.size() + N)N 的值是 distance(i, j)
  • 另外emplace、emplace_hint、insert的要求都在表102中。
猜你喜欢
  • 2023-04-09
  • 1970-01-01
  • 2012-03-04
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
  • 2016-02-26
相关资源
最近更新 更多