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

本文介绍了如何在C++中使用map和set来创建排行榜,并详细解释了两种实现方式:重载关系运算符和自定义functor。通过实例展示了如何根据分数、时间戳和用户ID进行排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 函数介绍


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值