您的位置:首页 > 其它

元素为自定义复合结构时 map,set 如何处理重复 key 及排序?

2015-07-26 13:50 471 查看
map, set 为 类模板,创建对象时需要指定 comparator, 如果不指定,默认使用 less. 因此,我们有 2 中方式可以选择:

1. 采用默认的 less, 我们需要重载关系运算符 "<". 但是我们不推荐这样做,这种方式可读性很差,因为我们从代码上根本看不出来 "<" 在哪里被调用;

2. 指定 functor, 传入的是一个functor 类名,而不是一个函数或 functor 对象。

下面的例子是一个排行榜,排序规则如下:

1. 按分数由高到低排;

2. 分数一样的情况下,按时间由新到旧排;

3. 时间也一样的情况下,按用户 ID 由小到大排。

方法一:重载 "<"

#include <iostream>
#include <map>

namespace test
{
// sorted by score in descending order  >
// then sorted by timestamp in descending order >
// then sorted by id in ascending order
class UserRank
{
public:
UserRank(int id, int score, int timestamp) : id(id), score(score), timestamp(timestamp) { }
~UserRank() { }

// The default comparator of map(set) is class template "less",
// for user defined types, you must overload operator "<".
friend bool operator<(const UserRank& left, const UserRank& right);
friend void PrintUserRank(const UserRank& userRank);

private:
int id;
int score;
int timestamp;
};

bool operator<(const UserRank& left, const UserRank& right)
{
if (left.score == right.score)
{
if (left.timestamp == right.timestamp)
{
return (left.id < right.id);
}
else
{
return (left.timestamp > right.timestamp);
}
}
else
{
return (left.score > right.score);
}
}

void PrintUserRank(const UserRank& userRank)
{
std::cout << "id: " << userRank.id << ", "
<< "score: " << userRank.score << ", "
<< "timestamp: " << userRank.timestamp << std::endl;
}
}

int main()
{
///////////////////////////////////////////////////////
std::map<test::UserRank, int> rankList;

test::UserRank user1(1, 100, 2015);
test::UserRank user2(1, 100, 2015);
test::UserRank user3(1, 100, 2014);

rankList[user1] = 1;
rankList[user2] = 2;
rankList[user3] = 3;

std::cout << rankList[user1] << std::endl;   // 2
std::cout << rankList[user2] << std::endl;   // 2
std::cout << rankList[user3] << std::endl;   // 3

///////////////////////////////////////////////////////
// check order
test::UserRank user4(1, 100, 2015);
test::UserRank user5(1, 200, 2015);
test::UserRank user6(1, 200, 2014);
test::UserRank user7(2, 200, 2014);

rankList.clear();
rankList[user4] = 1;
rankList[user5] = 2;
rankList[user6] = 3;
rankList[user7] = 4;

for (std::map<test::UserRank, int>::iterator it = rankList.begin();
it != rankList.end(); ++it)
{
PrintUserRank(it->first);
}

return 0;
}


方法二:自定义 functor

#include <iostream>
#include <map>

namespace test
{
// sorted by score in descending order  >
// then sorted by timestamp in descending order >
// then sorted by id in ascending order
class UserRank
{
public:
UserRank(int id, int score, int timestamp) : id(id), score(score), timestamp(timestamp) { }
~UserRank() { }

// The default comparator of map(set) is class template "less",
// for user defined types, you must overload operator "<".
friend struct UserComp;
friend void PrintUserRank(const UserRank& userRank);

private:
int id;
int score;
int timestamp;
};

struct UserComp
{
bool operator()(const UserRank& left, const UserRank& right)
{
if (left.score == right.score)
{
if (left.timestamp == right.timestamp)
{
return (left.id < right.id);
}
else
{
return (left.timestamp > right.timestamp);
}
}
else
{
return (left.score > right.score);
}
}
};

void PrintUserRank(const UserRank& userRank)
{
std::cout << "id: " << userRank.id << ", "
<< "score: " << userRank.score << ", "
<< "timestamp: " << userRank.timestamp << std::endl;
}
}

int main()
{
///////////////////////////////////////////////////////
std::map<test::UserRank, int, test::UserComp> rankList;

test::UserRank user1(1, 100, 2015);
test::UserRank user2(1, 100, 2015);
test::UserRank user3(1, 100, 2014);

rankList[user1] = 1;
rankList[user2] = 2;
rankList[user3] = 3;

std::cout << rankList[user1] << std::endl;   // 2
std::cout << rankList[user2] << std::endl;   // 2
std::cout << rankList[user3] << std::endl;   // 3

///////////////////////////////////////////////////////
// check order
test::UserRank user4(1, 100, 2015);
test::UserRank user5(1, 200, 2015);
test::UserRank user6(1, 200, 2014);
test::UserRank user7(2, 200, 2014);

rankList.clear();
rankList[user4] = 1;
rankList[user5] = 2;
rankList[user6] = 3;
rankList[user7] = 4;

for (std::map<test::UserRank, int>::iterator it = rankList.begin();
it != rankList.end(); ++it)
{
PrintUserRank(it->first);
}

return 0;
}


延伸阅读:

函数调用符重载

【STL】<algorithm><numeric><functional> 中的常用算法

【map】【set】poj 3297

STL中map,multimap,set,multiset,unordered_map,unordered_multimap,unordered_set,unordered_multiset的实现方法

STL map, multimap, set, multiset 函数介绍
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: