题目

编写程序,设计包含考生 ID、姓名与总分的结构体 Student,并存入 std::set 与 std::map。重载 operator< 或自定义仿函数作为比较谓词,实现:分数从高到低降序排列,分数相同时按工号升序排。重点阐述 STL 关联容器基于“严格弱序”(Strict Weak Ordering)判定两元素等价的机制(!(a < b) && !(b < a)),演示若小于号重载缺少自反性(a < a 为真)导致的去重失效与红黑树死循环。

输入格式:无需外部输入。

输出格式:输出按自定义严格弱序多级排序后的考生排名榜。

数据范围与约定:红黑树比较谓词与严格弱序数学准则。

思路与算法

1. 严格弱序四大准则
必须满足:①反自反性(x < x 必须为 false);②非对称性;③传递性;④等价传递性。若误写成 <=,则 x <= x 为真,红黑树在平衡旋转时将崩溃。

2. STL 的等价而非相等
std::set 并不调用 == 判断重复,而是如果 !(a < b) && !(b < a) 成立,就认定两者等价!因此在多属性排序中,必须确保所有属性完全一致才返回 false。

3. std::tie 极简多级比较
在实现复杂多字段比较时,借用 std::tie(b.score, a.id) < std::tie(a.score, b.id) 能自动完成严格的字典序多级比对,代码极其优雅且杜绝 Bug。

完整程序

#include <iostream>
#include <set>
#include <string>
#include <tuple>

struct Student {
    int id;
    std::string name;
    int score;

    // 自定义严格弱序:成绩降序;若成绩并列,按工号 id 升序
    bool operator<(const Student& other) const {
        // 利用 std::tie 构造反向元组实现降序比对
        return std::tie(other.score, id) < std::tie(score, other.id);
    }
};

int main() {
    std::set<Student> ranking;

    ranking.insert({1003, "张三", 85});
    ranking.insert({1001, "李四", 92});
    ranking.insert({1004, "王五", 85}); // 成绩与张三相同,比对 id 1003 < 1004
    ranking.insert({1002, "赵六", 98});
    ranking.insert({1001, "重复李四", 92}); // 相同 id 与成绩,命中等价去重

    std::cout << "--- 成绩排行榜(成绩降序,并列按 ID 升序) ---\n";
    int rank = 1;
    for (const auto& s : ranking) {
        std::cout << "第 " << rank++ << " 名: ID=" << s.id 
                  << " \t姓名: " << s.name << " \t成绩: " << s.score << "\n";
    }

    std::cout << "\n有效记录数: " << ranking.size() << " (成功去重并有序)\n";

    return 0;
}

运行示例

输出:

--- 成绩排行榜(成绩降序,并列按 ID 升序) ---
第 1 名: ID=1002 	姓名: 赵六 	成绩: 98
第 2 名: ID=1001 	姓名: 李四 	成绩: 92
第 3 名: ID=1003 	姓名: 张三 	成绩: 85
第 4 名: ID=1004 	姓名: 王五 	成绩: 85

有效记录数: 4 (成功去重并有序)