std::map::upper_bound 与 std::upper_bound 性能

Posted

技术标签:

【中文标题】std::map::upper_bound 与 std::upper_bound 性能【英文标题】:std::map::upper_bound vs std::upper_bound performance 【发布时间】:2020-01-18 09:53:05 【问题描述】:

在一些 CP 比赛中(这很重要),我使用了 2 个版本的 upper_bound 在我的 std::map 中找到上限:

算法上限(1)

auto itr = std::upper_bound(s.begin(),s.end(), somenumber);

if(itr == s.end() || *itr > somenumber2)

//dosth
 else
//dosth2

std::map::upper_bound (2):

auto itr = s.upper_bound(somenumber);

if(itr == s.end() || *itr > somenumber2)

//dosth
 else
//dosth2

如果我手动输入少量输入,这两个版本都可以使用。但是当涉及到~500.000 时,输入 (1) 超过了时间限制 (4 seconds) 但 (2)0.5/4.0 second 中完成了工作。 我查看了文档 algorithm/upper_bound 和 map/upper_bound 并且都具有 O(c log(n)) 复杂性(我认为在这两种情况下 c 应该是相似的。所以问题是 - 是什么导致了这种差异?

【问题讨论】:

【参考方案1】:

cppreference page for std::upper_bound 表示完成的比较次数是对数,但它也继续:

但是,对于非 LegacyRandomAccessIterators,迭代器增量的数量是线性的。

std::map 没有随机访问迭代器,因此std::upper_bound 将允许由于增量而在迭代器距离上具有线性时间复杂度,而std::map::upper_bound 需要在容器大小上具有对数时间复杂度.

【讨论】:

我已经读过 - 我认为由于 map::upper_bound 中的对数时间存在一些 std::upper_bound 的专业化地图。好的,现在很清楚并理解为什么在std::map 中存在特殊版本的upper_bound 并且算法upper_bound 仅在一般情况下有效(没有关于某些STL 结构的任何额外信息)。 @mvxxx 在该实践的标准库中还有其他示例。例如:std::sortstd::list::sort @mvxxx 我现在不确定,但可能有一些神秘的原因,使用 std::upper_boundstd::map 特定算法在提供 std::map 迭代器时会使实现不合格. 也许是为了某种哲学?来自algorithm 的 std:: 应该在一般情况下有效,并且我们可以在某些结构中进行的每个提升(使用有关它们的额外信息)都应该作为给定结构的方法来完成? @walnut 据我了解map::upper_bound 从根节点开始执行树搜索(假设map 实现为红黑树)。这也是map::upper_bound 不接受迭代器对的原因(它总是搜索整个容器)。 std::upper_bound 更通用,这就是它不使用 map::upper_bound 的原因。

以上是关于std::map::upper_bound 与 std::upper_bound 性能的主要内容,如果未能解决你的问题,请参考以下文章

什么是C/S模式与B/S模式,两者区别与优缺点

Java 中的正则表达式,\\s 与 \\s+

C/S与B/S架构 区别·与优点

深入理解B/S与C/S架构

概率与期望

s = s + 1 与 s += 1的区别