【问题标题】:Computational time complexity of std::map::mergestd::map::merge 的计算时间复杂度
【发布时间】:2018-08-15 13:23:40
【问题描述】:

C++17 引入了一个 std::map::merge 函数,用于将一个 std::map 合并到另一个中。

由于std::map 是一个有序的关联容器,更明确地说是一个自平衡二叉搜索树(最常实现为红黑树或AVL 树),我希望@987654325 @ 利用了 std::maps 的元素都已经排序的事实,因此不需要搜索每个元素的插入位置,即时间复杂度应该线性摊销 O(N)

有趣的是,cppreference saysstd::map::merge 的计算时间复杂度是对数O(N*log(N))

复杂度 N*log(size()+N)),其中N是source.size()

对吗?

在这种情况下std::map::merge 似乎等同于std::map::insert(iterator begin, iterator end),使得std::map::merge 完全多余。

std::map::merge 的时间复杂度的真相是什么?

【问题讨论】:

  • 该方法是作为批量拼接的包装器引入的,而不是利用两个容器的排序特性。它没有假设比较器彼此同步。
  • @AnT 是的,但它可以很容易地通过承诺比较器是同步的,例如使用标签调度来解决。
  • 也许有一个专门针对两个地图使用相同比较器的情况,但这不会改变通常复杂性更差的事实
  • @user463035818 比较器通常被认为是有状态的对象。相同类型的两个比较器不必产生相同的顺序。
  • @AnT 是的,没有考虑到这一点。可以想象,有状态的比较器很难确保严格的弱排序

标签: c++ binary-search-tree std c++17 stdmap


【解决方案1】:

我希望 std::map::merge 能够利用以下事实: 两个 std::maps 的元素都已经排序,所以不需要 搜索每个元素的插入位置 [...]

您错过了要合并的地图可能属于不同类型的事实,即它可能使用不同的排序:

template <class C2>
void merge(std::map<Key, T, C2, Allocator>& source); 
                            ^--- this is not necessarily the same as for the map you 
                                 are merging into

所以实际上要合并的地图必须被视为未排序以获得最坏情况的复杂性。

【讨论】:

  • 它们可以为比较器类型相同的情况提供重载。无论如何,有状态的比较器仍然有可能处于不同的状态,无论它们的类型是否相同。不过,它可以很容易地通过使用标签调度来保证比较器是同步的,例如std::map::merge(map, comp_sync_tag)
  • @plasmacel 实际上不再确定您的问题是什么......两个地图可以在线性时间内合并吗?是的。 std::map::merge 是线性的吗?没有。
  • 你回答了这个问题。我只是说这个功能从弱设计中散发出来。它缺少一些非常有用的功能,就像std::vector 缺少一个不会初始化的resize 函数一样。有时std 的不完整性确实让我感到惊讶。
  • @plasmacel 我可以想象原因是,如果您有两个相同类型的地图,那么合并它们几乎是微不足道的,并且没有迫切需要将方法引入标准
  • 是的,使用std::map::insert(hint, value),其中hint 是另一个映射的end() 迭代器在恒定时间内执行按顺序插入 - 使用这一事实可以执行合并(通过插入另一个地图的项目一个接一个)在线性时间内。
【解决方案2】:

想象一下这个方法的可能实现:

for (auto const& iter : source)
{
   dest. insert( iter);
}

因此,您遍历源映射(复杂度 N),并将每个元素插入到具有复杂度 log(dest.size()+N) 的目标映射中。
正如 user463035818 的另一个答案已经指出的那样,两个映射的顺序不一定相同,因此您必须分别插入每个元素。
最后,树排序算法必须以一种方式构建,即您从根节点向下遍历树并在向下或再次返回时进行平衡。很难编写一个按顺序遍历树、添加元素平衡树的算法。

【讨论】:

    猜你喜欢
    • 2012-04-15
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    • 2011-06-21
    相关资源
    最近更新 更多