c ++ STL按int和string的向量排序

时间:2012-07-18 00:20:52

标签: c++ algorithm stl

今天我在topcoder上解决了一个问题,我必须在奥运会上用奖牌对国家进行排序。我有一个STL容器vector<pair<vector<int>, string> > v; vector<int>不包含一个国家赢得的金,银和铜牌。我必须按照金,银,铜和国家(字母顺序)的特定顺序对结构进行排序。

我使用了sort(v.begin(),v.end())但是这只按照对中的第一个值排序,即按金,银和铜排序,而不是按g,s的字母顺序排序国家,两个国家的奖牌是相同的。

3 个答案:

答案 0 :(得分:3)

您必须提供比较功能对象。

typedef pair<vector<int>, string> Country;
struct CmpCountry {
    bool operator()(const Country& lhs, const Country& rhs)
    {
        if(lhs.first[0] != rhs.first[0])
            return lhs.first[0] > rhs.first[0];
        if(lhs.first[1] != rhs.first[1])
            return lhs.first[1] > rhs.first[1];
        if(lhs.first[2] != rhs.first[2])
            return lhs.first[2] > rhs.first[2];
        return lhs.second < rhs.second;
    }
};

// then, call sort as following
std::sort(v.begin(), v.end(), CmpCountry());

答案 1 :(得分:2)

如果您实际编写了所描述的代码,它将完全符合您的要求:

compare.cpp:

#include <vector>
#include <utility>
#include <algorithm>
#include <iostream>

using namespace std;

typedef pair<vector<int>, string> Country;

int main(int, char*[]) {
  vector<Country> v;
  while (cin.good()) {
    string name;
    int g, s, b;
    cin >> name >> g >> s >> b;
    vector<int> c;
    c.push_back(g);
    c.push_back(s);
    c.push_back(b);
    v.push_back(make_pair(c, name));
  }
  sort(v.begin(), v.end());
  for (vector<Country>::const_iterator it = v.begin(); it != v.end(); ++it) {
    cout << it->second << " " << it->first[0]
     << " " << it->first[1] << " " << it->first[2] << "\n";
  }
  return 0;
}

compare.in:

US 3 2 1
CA 4 1 3
DE 1 3 5
FR 1 3 5
BE 1 3 5
RU 3 1 2

现在这样做:

$ clang++ -o compare compare.cpp
$ ./compare < compare.in
BE 1 3 5
DE 1 3 5
FR 1 3 5
RU 3 1 2
US 3 2 1
CA 4 1 3

请注意,首先按金牌排序(升序)(首先是BE / DE / FR,然后是RU / US,然后是CA),接下来是银(RU然后是美国),接下来是铜牌(虽然这没有出现用我的输入),然后命名(BE,然后是DE,然后是FR)。正是你所要求的。

(嗯,实际上你要求按字母顺序排列,这将为g,s和b做数字顺序。这可能是你想要的(例如,2枚金牌超过11枚)。不,你必须编写自己的比较函子,在比较之前对整数进行字符串化。)

那么,为什么这有效呢?好吧,如果你看一下std::pair的定义,它会按字典顺序进行比较 - 也就是说,它比较lhs.firstrhs.first,然后转到lhs.second vs 。rhs.second只有first s相等。如果你看一下std::vector的定义,它也会按字典顺序进行比较 - 也就是说,比较lhs[0]rhs[0],然后转到lhs[1] vs.仅当rhs[1] s相等时才[0],依此类推。而这正是你在此之后的比较顺序。

根据您的评论,听起来您想要反转数值的正常排序顺序,而不是国家/地区名称。要做到这一点,你必须定义自己的比较器。但请注意,问题不在于对和向量不按您想要的方式排序 - 他们这样做 - 但是int并没有按照您想要的方式排序。

如果您理解这一点,这一切都非常微不足道,而不仅仅是给出答案,我将逐步解释。

首先,这是默认排序(实际上,不是字面意思)要做的事情:

struct CountryComparator {
  bool operator()(const Country& lhs, const Country& rhs) const {
    if (!(lhs.first == rhs.first))
      return (lhs.first < rhs.first);
    return (lhs.second < rhs.second);
  }
};

(请注意,我只会使用==<。这在您的情况下无关紧要,因为您只是比较一下,但是STL是专门设计的围绕这样的想法,即每个算法都应该在仅支持这两个运算符的类上工作,并且这是一个很好的习惯。)

扩展矢量比较会使事情变得非常冗长,所以我们不要打扰。如果你真的想要反转向量的某些成员而不是其他成员的排序顺序,你必须这样做,但是你试图反转整个向量的排序顺序,这与只是反转排序相同矢量本身的顺序。所以,只需定义一下:

struct CountryComparator {
  bool operator()(const Country& lhs, const Country& rhs) const {
    if (!(lhs.first == rhs.first))
      return (rhs.first < lhs.first);
    return (lhs.second < rhs.second);
  }
};

现在,只需将排序行更改为:

  sort(v.begin(), v.end(), CountryComparator());

现在让我们试一试:

$ ./compare < compare.in
CA 4 1 3
US 3 2 1
RU 3 1 2
BE 1 3 5
DE 1 3 5
FR 1 3 5

拥有4枚金币的CA领先于其他所有人。然后美国和RU,每个3金,按银子分类;拥有2个银牌的美国排在第一位。然后BE,DE和FR,每个1金,相同数量的银子和相同数量的青铜器按字母顺序排序。

答案 2 :(得分:0)

您需要一个自定义比较器,以便STL排序可以比较您的向量。最简单的方法是将矢量定义为struct,然后添加比较器。

struct country {
    vector<int> medals;
    string country_name;
}

struct compare { 
    bool operator()(country const &a, country const &b) { 
        for(int i = 0; i <  3; i++){ // 3 medals, right?
            if(a.medals[i] != b.medals[i]) 
                return a.medals[i] < b.medals[i];
        //else both countries have same number of medals
        return a.country_name < b.country_name;
    }
};