std :: sort(stable_sort)比较函数返回值的结果令人困惑

时间:2018-11-12 01:34:49

标签: c++ sorting std c++-standard-library

我有以下简单程序。在test1test2中,我尝试对2个字符串“ 2”和“ 1”进行排序,在下面的示例中,函数compare将始终返回false。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cassert>

static inline bool compare(const std::string& a, const std::string& b)
{
    if (isdigit(b[0]))
        return false;

    assert(isdigit(a[0]));
    return true;
}

static inline void test1()
{
    std::cout << "test1:\n";
    std::vector<std::string> arr = {
            "2", "1"
    };
    std::stable_sort(arr.begin(), arr.end(), compare);
    for (auto e: arr)
        std::cout << e << std::endl;
}

static inline void test2()
{
    std::cout << "test2:\n";
    std::vector<std::string> arr = {
            "1", "2"
    };
    std::stable_sort(arr.begin(), arr.end(), compare);
    for (auto e: arr)
        std::cout << e << std::endl;
}

static inline bool compare_int(const int& a, const int& b)
{
    return a > b;
}

static inline void test3()
{
    std::cout << "test3:\n";
    std::vector<int> arr = {
            9, 3, 13, 7
    };
    std::stable_sort(arr.begin(), arr.end(), compare_int);
    for (auto e: arr)
        std::cout << e << ' ';
    std::cout << std::endl;
}

int main()
{
    test1();
    test2();
    test3();

    return 0;
}

但是,我得到以下输出

test1:
2
1
test2:
1
2
test3:
13 9 7 3 

我很困惑,因为据我所知,test1和test2中的compare函数将返回false,这表明这两个元素应该交换它们的位置。但是显然,它们没有改变,仍然保留在原始位置。

我误解了比较函数的返回值吗?但是在test3中,它确实是按降序排序的。

我不太了解其内部结构,它是否以不同于整数的方式对待字符?

2 个答案:

答案 0 :(得分:2)

我要回答自己的问题,但是非常感谢PaulMckenzie在讨论中的帮助以及Victor Istomin的回答。

事实证明,这种排序方式并不符合我的预期。它期望严格弱阶,这意味着a > bb > a 不能同时为真,否则行为为未定义。另外,它判断2个元素是否相等的方法是使用!(a < b) && !(b > a),因为它仅使用<运算符而不是==运算符。

我的代码中的错误是,在这种情况下,我总是返回false,这样表达式!(a < b) && !(b > a)将为true,并且sort认为它们相等,因此不进行交换。

PaulMckenzie指出,正确的解决方案是使用stable_partiion(如果不需要相对顺序,则使用partition)。原理是仅在我们有比较元素的明确规则时才使用排序,如果我们只想将相同元素分组在一起,则partition是好的。

似乎我对排序函数有一些错误的幻想,谢谢指出。

-----------------更新----------------

Caleth在评论中指出,严格弱顺序未强制执行,但如果违反,行为将是不确定的。更新了我对该部分的描述。谢谢。

答案 1 :(得分:0)

“比较”功能与您编写的功能完全相同:如果第二个字符串的第一个字符为digit,则返回false。

顺便说一句,在一般情况下,此比较功能将无法按预期运行(无论您期望如何,我都不知道)。在C ++中,排序比较器应实施严格的弱排序。换句话说,不应同时存在“ a