问题 std :: is_sorted和严格的比较少?


我不太了解 std::is_sorted 算法及其默认行为。如果我们期待 cppreference,它默认说 std::is_sorted 使用 < 运营商。而不是那样,我发现使用 <= 会是很自然的。但我的问题是,对于以下数字列表:

1 2 3 3 4 5

它会回来 true, 即使 3 < 3 应该 false。怎么可能?

编辑:它似乎比我想象的更糟糕,因为传递 std::less_equal<int> 在那种情况下将返回false ...当我通过比较器函数时应用的条件是什么?


4401
2017-07-21 04:40


起源

有效的STL 作者:Scott Meyers,第19项:“理解等同与平等之间的区别” - TemplateRex


答案:


每25.4 / 5:

序列相对于比较器排序 comp 如果是的话   迭代器 i 指向序列和任何非负整数 n   这样的 i + n 是一个指向元素的有效迭代器   序列, comp(*(i + n), *i) == false

因此对于

1 2 3 3 4 5

std::less<int>()(*(i + n), *i) 将返回 false 对全部 n,而 std::less_equal 将返回 true 为了案件 3 3


10
2017-07-21 05:00



好吧,它现在有意义,即使它对我来说是违反直觉的。 - Vincent
@Vincent,直到我查看标准时,它对我来说都是反直觉的:) - soon
我觉得如果我在所有答案中都有一个标准的引用,我的代表会更高 - aaronman
@aaronman当标准如此清晰时,我认为没有比这更好的答案了。 - Vincent
@Vincent我只想指出paxdiablos的回答是第一次,我编辑了之后,他说同样的话没有标准报价 - aaronman


即使你只有 < 运算符,你可以弄清楚两个数字是否相等,不一定相等。

if !(first < second) and !(second < first)
then first equivalent to second
 

另外,正如paxdiablo首先提到的解决方案,你可以实现 is_sorted 随着列表上升并不断检查 < 不是真的,如果真的你停下来。

以下是cplusplus.com中该函数的正确行为

template <class ForwardIterator>
  bool is_sorted (ForwardIterator first, ForwardIterator last)
{
  if (first==last) return true;
  ForwardIterator next = first;
  while (++next!=last) {
    if (*next<*first)     // or, if (comp(*next,*first)) for version (2)
      return false;
    ++first;
  }
  return true;
}  

4
2017-07-21 04:44



我知道,但我认为 std::is_sorted 会回来的 true 如果提供的条件是 true 对全部 (N, N+1) 元素,情况并非如此。 - Vincent
@Vincent没有关注你能否详细说明 - aaronman
如果我通过比较器 std::less<int>,比较将返回: true 对于 (1, 2), true 对于 (2, 3) 但 false 对于 (3, 3),所以我认为算法在这里停止(首先 false检测到并返回 false。但事实并非如此。 - Vincent
有效的STL 作者:Scott Meyers,第19项:“理解等同与平等之间的区别”特别是 !(a < b) && !(b < a) 并不意味着 a == b 但只有这一点 a 和 b 是 当量。对于内置类型,这些概念重合但不一定适用于类类型。等价对分区很有用(例如 std::multiset 容器和 std::partition 算法) - TemplateRex
平等和等同之间的细微差别是例如 stable_sort 和 sort。这根本不是挑剔(除非你考虑Scott Meyers写作 挑剔的书)!我必须对你的答案进行投票,但如果你改变它以反映这些概念,我会赞成它。 - TemplateRex


你好像假设它正在检查(对于肯定的情况),如果元素N小于元素N + 1,那么所有元素都是最后一个。这确实不适合 <,虽然你可以使用'技巧'来评估 <= 同 < 和 !:以下两个是等价的:

if (a <= b)
if ((a < b) || (!((b < a) || (a < b)))) // no attempt at simplification.

但是,它更有可能检测到(否定情况)如果元素N小于第一个元素N-1,那么它可以在发现违规时立即停止。那 能够 无所不能 <,像(伪代码):

for i = 1 to len - 1:
    if elem[i] < elem[i-1]:
        return false
return true

2
2017-07-21 04:46