std :: is_sorted

时间:2019-06-20 14:12:33

标签: c++ algorithm sorting compare assert

我正在学习c ++中的断言,并且遇到了std :: is_sorted的怪异行为。

给出一个比较器(c)和std :: strings的未排序向量(v)。我使用std :: sort(v.begin(),v.end(),comparator)。然后使用相同的参数调用std :: is_sorted。结果是错误的,为什么呢?

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <cassert>
int main(){
    auto comparator([](std::string a , std::string b) {return a.length() - b.length();} );
    std::vector<std::string> v {"y" , "yyyy" , "yy" ,
                                 "yy" , "yyyyyyy" , "yyy"};
    assert(false == std::is_sorted(v.begin() , v.end(),comparator));
    std::sort(v.begin(), v.end(),comparator);
    assert(true == std::is_sorted(v.begin() , v.end(),comparator));
}

2 个答案:

答案 0 :(得分:6)

您的谓词无法正常工作。如果要按字符串长度排序,则需要

auto comparator([](std::string a , std::string b) {return a.length() < b.length();} );

您发布的原始谓词返回字符串长度差,该字符串长度差是整数类型,在被bool调用时可以转换为std::sort,并且对于所有不同的内容确实会导致true0,否则为false。因此,每个不相等的字符串长度都会导致谓词被评估为true,并且由于谓词一直都为“ true”,因此具有不同字符串长度的序列元素将被无限交换。这将导致不确定的行为。

此处的术语是谓词必须实现“严格弱排序”,例如,在cppreference上。感谢@FrançoisAndrieux和@Peter在这方面的评论。

还考虑通过const std::string&std::string_view传递参数,以避免不必要的复制。

答案 1 :(得分:2)

根据C ++标准( 28.7排序和相关操作

  

2 Compare是函数对象类型(23.14)。 的返回值   在以下情况下,将函数调用操作应用于“比较”类型的对象   上下文转换为布尔值(第7条),如果第一个   调用的参数小于第二个参数,否则为false。   假设有序,在算法中始终使用Compare comp   关系。假定comp不会应用任何非常数   通过取消引用的迭代器来实现功能。

此lambda表达式

auto comparator([](std::string a , std::string b) {return a.length() - b.length();} );

如果两个字符串的长度不相等,则总是返回(根据上下文转换的值)true

所以对于这个向量

std::vector<std::string> v {"y" , "yyyy" , "yy" ,
                             "yy" , "yyyyyyy" , "yyy"};

lambda表达式在位置false"yy"处的相邻元素"yy"2中返回3

例如,如果您要在位置2和3之间放置一个中间值,例如

std::vector<std::string> v {"y" , "yyyy" , "yy" , "y",
                             "yy" , "yyyyyyy" , "yyy"};

然后是第一个断言

assert(false == std::is_sorted(v.begin() , v.end(),comparator));

失败。

因此,您需要正确定义比较功能。例如

auto comparator( []( const std::string &a , const std::string &b ) 
                 {
                     return a.length() < b.length(); 
                 } );

lambda表达式的参数也应该是常量引用。

请注意,如果您的编译器支持C ++ 17,那么您还可以按照以下方式重写lambda表达式

auto comparator( []( const std::string &a , const std::string &b ) 
                 {
                     return std::size( a ) < std::size( b ); 
                 } );