多属性排序是反转元素

时间:2014-12-30 20:37:03

标签: c++ sorting

我正在尝试对某些数据实施多属性排序,并通过背靠背stable_sorts来解决问题:

bool DecreasingA(const Data & a, const Data & b) {
    return a.A >= b.A;
}

bool DecreasingB(const Data & a, const Data & b) {
    if (a.B)
        return true;  // if a.B is true, maintain ordering
    if (b.B)
        return false; // a.B is false, but b.B is true, to swap elements
    return true;      // a.B and b.B are false, maintain ordering
}

std::vector<Data> myVector;

// add Data to vector here

std::stable_sort(myVector.begin(), myVector.end(), DecreasingA());
std::stable_sort(myVector.begin(), myVector.end(), DecreasingB());

但是在我这样做之后,myVector的A属性与我想要的顺序相反。即使它在第一个stable_sort

之后正确排序

例如:

在排序之前:

A B C

1 0 5
1 1 8
2 0 2
0 1 3

第一次排序(减少A)看起来不错:

A B C

2 0 2
1 0 5
1 1 8
0 1 3

第二次排序后(减少B)我得到了这个:

A B C

0 1 3
1 1 8
1 0 5
2 0 2

而不是我想要的:

A B C

1 1 8
0 1 3
2 0 2
1 0 5

我认为这是我的DecreasingB函数的一个问题,但我尝试了各种逻辑并继续进行这种反转。有什么建议吗?

我知道我可以编写一个比较函数来处理这种特殊情况,但我需要灵活性让最终用户选择要排序的属性以及它们应用的顺序。

3 个答案:

答案 0 :(得分:6)

您的比较功能都已损坏。都没有实现std::stable_sort所要求的必要的严格弱排序。具体来说,

  • 反身性:f(x, x)必须是假的。
  • 反对称:f(x, y)暗示!f(y, x)

两个帐户的功能都失败了。

你可能想要这个:

bool DecreasingA(const Data & a, const Data & b) {
    return a.A > b.A;  // > instead of >=
}

bool DecreasingB(const Data & a, const Data & b) {
    if (a.B == b.B)   // both equal, so a does not precede b
        return false;
    if (b.B)          // b.B is true and a.B is false, so a does not precede b
        return false; 
    return true;      // a.B is true and b.B is false, so a does precede b
}

答案 1 :(得分:2)

您只需撰写DecreasingBThenA

即可
#include <algorithm>
#include <tuple>
#include <vector>
#include <iostream>

struct Data
{
    int A, B, C;    
};

bool DecreasingBThenA(const Data & a, const Data & b) 
{
    return std::tie(a.B, a.A) > std::tie(b.B, b.A);
}

int main()
{    
    auto myVector = std::vector<Data> 
    {{ 1, 0, 5}, {1, 1, 8}, {2, 0, 2}, {0, 1, 3}};

    std::stable_sort(myVector.begin(), myVector.end(), DecreasingBThenA);

    for (auto&& t : myVector)
        std::cout << "{" << t.A << ", " << t.B << ", " << t.C << "}\n";
}
产生所需输出的

Live Example

如果N中有Data个元素,并且您希望能够进行任意排序,那么您所需要的只是DecreasingADecreasingN的比较(每个返回a.X > b.X数据成员X),然后使用您想要排序的条件的逆序中的std::sort进行多次传递。因此,BThenA需要先A然后B进行排序。这与使用逐列排序按钮同时在各种列上对Excel中的数据进行排序的方式相同。

答案 2 :(得分:1)

DecreasingA不提供排序算法所要求的严格弱排序,因此无法保证任何特定行为。