尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

C++中set与map的自定义排序方法详解

C++中set与map的自定义排序方法详解
📅 发布时间:2026/6/20 6:21:49

在C++标准模板库(STL)中,set和map是两种常用的关联容器,它们默认按照键的升序进行排序。但在实际开发中,我们经常需要根据特定需求对元素进行自定义排序。本文将详细介绍如何为set和map实现自定义排序。

默认排序行为

在深入了解自定义排序之前,我们先看一下set和map的默认行为:

#include <iostream>
#include <set>
#include <map>int main() {// 默认升序排列的setstd::set<int> defaultSet = {3, 1, 4, 1, 5, 9};for (int num : defaultSet) {std::cout << num << " "; // 输出: 1 3 4 5 9}std::cout << std::endl;// 默认升序排列的mapstd::map<int, std::string> defaultMap = {{3, "three"},{1, "one"},{4, "four"}};for (auto& pair : defaultMap) {std::cout << pair.first << ":" << pair.second << " "; // 输出: 1:one 3:three 4:four}return 0;
}

实现自定义排序

C++提供了两种主要方式来实现自定义排序:

1. 使用函数对象(Functor)

函数对象是一个重载了函数调用操作符(())的类,可以作为比较器传递给set或map。

#include <iostream>
#include <set>
#include <map>// 降序排序的函数对象
struct DescendingOrder {bool operator()(int a, int b) const {return a > b; // 降序排列}
};// 按字符串长度排序的函数对象
struct StringLengthComparator {bool operator()(const std::string& a, const std::string& b) const {return a.length() < b.length(); // 按长度升序}
};int main() {// 使用自定义排序的set(降序)std::set<int, DescendingOrder> customSet = {3, 1, 4, 1, 5, 9};for (int num : customSet) {std::cout << num << " "; // 输出: 9 5 4 3 1}std::cout << std::endl;// 使用自定义排序的map(按字符串长度)std::map<std::string, int, StringLengthComparator> lengthMap;lengthMap["apple"] = 5;lengthMap["banana"] = 6;lengthMap["cherry"] = 6;lengthMap["date"] = 4;for (auto& pair : lengthMap) {std::cout << pair.first << ":" << pair.second << " "; // 输出: date:4 apple:5 banana:6 cherry:6// 注意:长度相同的元素,按字典序排列}return 0;
}

2. 使用Lambda表达式(C++11及以上)

C++11引入了Lambda表达式,可以更简洁地定义比较器。

#include <iostream>
#include <set>
#include <map>
#include <string>int main() {// 使用Lambda表达式定义降序排序auto descendingLambda = [](int a, int b) { return a > b; };std::set<int, decltype(descendingLambda)> lambdaSet(descendingLambda);lambdaSet.insert({3, 1, 4, 1, 5, 9});for (int num : lambdaSet) {std::cout << num << " "; // 输出: 9 5 4 3 1}std::cout << std::endl;// 对于map,使用Lambda按值排序(需要特殊技巧)std::map<std::string, int> normalMap = {{"apple", 5},{"banana", 2},{"cherry", 8},{"date", 3}};// 创建一个按值排序的"视图"auto valueComparator = [&normalMap](const std::string& a, const std::string& b) {return normalMap[a] < normalMap[b];};std::set<std::string, decltype(valueComparator)> valueOrderedSet(valueComparator);for (auto& pair : normalMap) {valueOrderedSet.insert(pair.first);}std::cout << "按值排序: ";for (auto& key : valueOrderedSet) {std::cout << key << ":" << normalMap[key] << " "; // 输出: banana:2 date:3 apple:5 cherry:8}return 0;
}

自定义对象排序

当set或map的元素是自定义对象时,自定义排序尤为重要。

#include <iostream>
#include <set>
#include <string>class Person {
public:std::string name;int age;Person(std::string n, int a) : name(n), age(a) {}
};// 按年龄排序的函数对象
struct AgeComparator {bool operator()(const Person& a, const Person& b) const {return a.age < b.age;}
};// 按姓名排序的函数对象
struct NameComparator {bool operator()(const Person& a, const Person& b) const {return a.name < b.name;}
};int main() {// 按年龄排序的setstd::set<Person, AgeComparator> ageSet;ageSet.insert(Person("Alice", 30));ageSet.insert(Person("Bob", 25));ageSet.insert(Person("Charlie", 35));std::cout << "按年龄排序: ";for (auto& person : ageSet) {std::cout << person.name << "(" << person.age << ") ";}std::cout << std::endl;// 按姓名排序的setstd::set<Person, NameComparator> nameSet;nameSet.insert(Person("Charlie", 35));nameSet.insert(Person("Alice", 30));nameSet.insert(Person("Bob", 25));std::cout << "按姓名排序: ";for (auto& person : nameSet) {std::cout << person.name << "(" << person.age << ") ";}return 0;
}

注意事项

  1. 严格弱序:自定义比较器必须满足严格弱序关系,即:

    • 非自反性:comp(a, a) 必须为false
    • 不对称性:如果comp(a, b)为true,则comp(b, a)必须为false
    • 可传递性:如果comp(a, b)为true且comp(b, c)为true,则comp(a, c)必须为true
  2. 相等判断:在set和map中,如果!comp(a, b) && !comp(b, a),则认为a和b相等(重复元素),不会被插入

  3. 性能考虑:比较器的性能会影响容器操作的效率,应确保比较操作尽可能高效

总结

C++中的set和map提供了灵活的自定义排序机制,可以通过函数对象或Lambda表达式实现。掌握这一特性可以让你更好地控制容器中元素的组织方式,满足各种复杂的业务需求。无论是基本数据类型还是自定义对象,都可以通过实现适当的比较器来定义排序规则。

在实际开发中,选择合适的数据结构和排序方式对程序性能和可维护性至关重要,希望本文能帮助你在使用set和map时做出更明智的选择。

相关新闻

  • id
  • 缺省源
  • MISC相关

最新新闻

  • MPC8641D双核SoC:嵌入式网络设计的集成化与多核编程实战
  • 6月西安奢侈品回收,闲置奢侈品包包手表首饰变现前先看看这篇 - 钦扬网络
  • 2026年6月评价高的别墅外墙石材/本地石材厂家推荐泌阳县丰源石业,加厚抗冻板材,北方低温户外不开裂不剥落 - 品牌鉴赏师
  • MAC7200微控制器时钟与复位机制深度解析与实战配置
  • 2026年详尽评测:10款好用的降AIGC软件,部分无限免费降AI!必看干货 - 降AI小能手
  • 2026南京品牌首饰保值白皮书,旧款磨损首饰,均按市场实价变现 - 讯息早知道

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号