【问题标题】:why c++ algorithm includes have at most 2*(count1+count2)-1 comparisons为什么 c++ 算法包含最多 2*(count1+count2)-1 个比较
【发布时间】:2015-12-07 13:39:23
【问题描述】:

在阅读cplusplus.com 文章时,我注意到它说如下:

在两个范围内以两倍的距离达到线性:最多执行 2*(count1+count2)-1 比较(其中 countX 是 firstX 和 lastX 之间的距离)。

但是,cppreference.com 表示:

最多 2·(N1+N2-1) 次比较,其中 N1 = std::distance(first1, last1) 和 N2 = std::distance(first2, last2)。

鉴于根据定义,N1 == Count1 和 N2 == Count2,哪个站点是正确的,任何人都可以解释这个最大数量或比较是如何计算的,即:

  1. 定义这种最大复杂性的最坏情况是什么
  2. 谁能解释该场景中的步骤,并显示上述哪个(cplusplus 或 cppreference)具有正确的比较次数?

【问题讨论】:

  • 您包含的链接向您展示了该功能的作用......
  • 另外,比起cplusplus,更喜欢cpprefence,最近一些资深成员告诉我,后者有时可能包含不好的做法甚至错误。 en.cppreference.com/w/cpp/algorithm/includes
  • @TuXiaomi 请重新阅读我的评论。
  • 我们可以重新打开这个问题吗?我认为这个问题现在已经很清楚了,答案真的很困扰我。

标签: c++ algorithm


【解决方案1】:

警告:在阅读过该主题的每个人都意识到他们不知道自己在说什么(包括我)之前,添加了此答案的声誉。如果将来某个时候有一个公认的答案与该算法的所有文档不矛盾,请多加注意!

简而言之:

2*(whatever) 位很容易解释,我在下面做了。 (无论如何)位让我非常困惑,据我所知应该是

2*(count1)

并且与第二个范围的长度完全无关。要么我遗漏了某些东西(很可能),要么文档有误(那不是很好......)。

如果您想了解我的推理,请参见下文。如果我错了并且有人有正确的答案,请告诉我,以便我删除此帖子!

为什么是 2 *(count1 等)

如果你问为什么是 2 次 (count1 + count2) -1,关键就在这一行:

第一个版本使用 operator

每次比较两个元素时,都会做两次比较:我不等于它,它不等于我。

这些“比较对”的最大数量很难确定。事实上,我想不通。据我所知,它应该与第二个范围的长度无关......

为什么不是 (count1 + count2 -1) 或 (count1 + count2) -1

我已经看了好几天,并根据cppreference 中的代码示例做了一些测试,老实说,我不知道这是怎么回事。

算法暗示并且 OP 挖出的消息来源说 range2 必须是 range1 的子集,并且两者都是排序的,因此没有必要检查元素两次。这意味着算法必须最多检查 range1 的所有元素,再加上一个额外的检查 range2 的元素是否大于 range1 中的任何元素。不仅如此,无论 range2 中有 2 个或 20 个元素,它仍然进行完全相同数量的比较。

比较有两种可能的定义,显然会给出不同的答案:

comparison == 算法中的所有比较操作

在这种情况下,会发生以下比较:

  1. 我是否到达了最后一个 range2 元素
  2. 我是否到达了最后一个 range1 元素
  3. 是 range2 elem
  4. 是 range2 elem > range1 elem

在简单的情况下 N1 == N2 == 1,这可以产生至少 6 次比较(例如,1、2、3、4、1、2:其中 range1 = {1} 和 range2 = {10} ),这远远超过任何一种算法所允许的。所以这不可能。

比较 == 检查 elem1 和 elem2 是否相等

在这种情况下,对 range1 的每个元素进行两次比较,直到找到 range2 的所有元素或到达 range1 的末尾并停止(发现它已到达 range1 的末尾)。

因此,据我所知,复杂度与N2的长度无关,复杂度应该是

2*(N1)

请注意,对于“比较”的这个定义,2*(N1 + N2 - 1) 似乎只适用于 N2 == 1,而 2*(N1 + N2) -1 永远不会作为比较次数成立仅在非最大复杂度情况下为奇数(range2 的数字不在 range1 内且不大于 max(range1))。

比较的任何其他定义都是有选择性的。我能想到的唯一另一件事是编译器优化了某些步骤,比如当元素没有增加时不检查它是否再次到达 range2 的末尾(这也会使算法根据需要依赖于 N2 ),但是我看不到任何其他可以优化的东西,以便将数字降低到完全匹配任一陈述的复杂性。

...其他人有更好的答案吗?我现在和 OP 一样好奇。

【讨论】:

  • range2 有两个 30,所以 range2 不包含在 range1 中。
  • @TuXiaomi : std::includes "如果排序范围 [first2, last2) 中的每个元素都在排序范围 [first1, last1) 中找到,则返回 true。" range2 不是 range1 的子集没关系,它只是检查每个元素是否存在于另一个范围内。
  • @I Stanley,感谢您的回复。
  • 对于[searchBeg,serchEnd)中的每个元素,[beg,end)中必须有一个相等的元素。如果[searchBeg,searchEnd)中的元素相等,则[beg,end)必须包含相同数量的元素。因此,[searchBeg, searchEnd) 必须是 [beg,end) Nicolai M. Josuttis 写在第 609 页,在 C++ 标准库,第 2 版,第 3 版中的子集。我在vs2015中写了一个程序,它证明range2必须是range1的子集,当return时:被包含。
  • 而cpprefernce.com表示复杂度为2·(N1+N2-1),而不是cpluscplus.com中的2·(N1+N2-)1
【解决方案2】:

首先,它必须进行 2 次比较来检查等价性,其定义为:

 if (!(a<b) && !(b<a))

if (!comp(a,b) && !comp(b,a))

然后它必须检查整个每个可能的范围,以相互减去 1。

【讨论】:

    【解决方案3】:

    关键在这一行

    如果 !(a

    让我们以 小于 谓词 sorted 集合为例

    [2,3]
    [1,2,3,4]
    

    比较元素 2 和 1:2

    最大比较次数:2*(M+N)-1。 算法运行时间为 O(N+M)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-19
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 2014-12-21
      • 1970-01-01
      • 2010-10-16
      • 2011-02-16
      相关资源
      最近更新 更多