对结构向量进行两次排序

时间:2018-08-18 18:29:42

标签: c++ algorithm sorting stl

假设我有一个结构向量

struct foo {
 int num;
 char s;
};

vector<foo> vec;

s可以是以下三个值之一:abc,而num可以是任何正整数或负整数。

我想要的是

首先,根据num对向量进行排序,然后对于num的每组重复值,根据s对它们进行排序,其中(a

我了解第一步很容易,并且可以通过谓词功能实现

bool compare (foo &a, foo &b) {
 if(a.num < b.num) return true;
 else return false;
}

std::sort(vec.begin(), vec.end(), compare)

我坚持的是第二部分。根据{{​​1}}对向量中的重复值进行排序。我尝试在此谓词中添加另一个条件,并为另一个排序步骤创建一个单独的谓词,但是我似乎缺少了一些东西。

非常感谢您的帮助。谢谢!

3 个答案:

答案 0 :(得分:3)

您可以将排序功能修改为:

    bool compare (foo &a, foo &b) {
       if(a.num < b.num) return true;
       else if(a.num == b.num) return a.s < b.s;

       return false;
    }

答案 1 :(得分:2)

如果要基于num进行排序,并且如果谓词中两个num的值都相等,则可以按s进行排序,这可以通过使用{{3} }

#include <tuple>
bool compare (foo &a, foo &b) 
{
   return std::tie(a.num, a.s) < std::tie(b.num, b.s);
}

如果您使用的是C ++ 98标准编译器而不是C ++ 11,则可以使用make_pair

完成相同的操作
#include <utility>
bool compare (foo &a, foo &b) 
{
   return std::make_pair(a.num, a.s) < std::make_pair(b.num, b.s);
}

与使用std::tie相比,我的偏好是std::make_pair。原因是,如果您在struct中添加了第三个成员,并且想在nums相等的情况下对该新成员进行排序,则使用{{1} }更易于更新,因为std::tie仅适用于两个值:

make_pair

答案 2 :(得分:1)

我不推荐这种方法,但是您可以可以使用两次sort调用:对内部元素进行一次排序,然后对外部元素进行稳定的排序(尽管这样会更慢):

std::sort(vec.begin(), vec.end(),
          [](foo const& f0, foo const& f1){ return f0.s < f1.s; });
std::stable_sort(vec.begin(), vec.end(),
          [](foo const& f0, foo const& f1){ return f0.num < f1.num; });

另一种方法是首先根据外部条件对元素进行排序,然后根据内部条件对相等范围(即,根据外部条件相等)进行排序:

auto outer_cond = [](foo const& f0, foo const& f1) {
    return f0.num < f1.num;
};

// sort elements according to the outer condition
std::sort(vec.begin(), vec.end(), outer_cond);

for (auto first = vec.begin(); first != vec.end();) {
    // find equal range
    first = std::adjacent_find(first, vec.end(),
                 [](foo const& f0, foo const& f1) { return f0.num == f1.num; });
    auto last = first;
    std::tie(first, last) = std::equal_range(first, vec.end(), *first, outer_cond);

    // sort equal range according to the inner condition
    std::sort(first, last,
              [](foo const& f0, foo const& f1) { return f0.s < f1.s; });

    first = last;
}

但是,使用合适的谓词对整个范围进行排序可能是最有效的。