标准::映射::合并的计算时间复杂度

Computational time complexity of std::map::merge

本文关键字:计算 时间复杂度 合并 映射 标准      更新时间:2023-10-16

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

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

有趣的是,cppreference说std::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的时间复杂度的实际真相是什么?

我希望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

因此,实际上必须考虑要合并的映射未排序以获得最坏情况的复杂性。

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

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

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