今天我在topcoder上解决了一个问题,我必须在奥运会上用奖牌对国家进行排序。我有一个STL容器vector<pair<vector<int>, string> > v;
vector<int>
不包含一个国家赢得的金,银和铜牌。我必须按照金,银,铜和国家(字母顺序)的特定顺序对结构进行排序。
我使用了sort(v.begin(),v.end())但是这只按照对中的第一个值排序,即按金,银和铜排序,而不是按g,s的字母顺序排序国家,两个国家的奖牌是相同的。
答案 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.first
与rhs.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;
}
};