STL map自定义排序规则

一、map自定义排序规则

map中存储的是key-value键值对,默认按照key值从小到大顺序排序。即map只能按照key排序。
pair的排序规则才是先按照key排,再按照value排序。

map<int, string> numAndPosMap{
    { 1, "aaa" },
    { 3, "bbb" },
    { 5, "ccc" },
    { 2, "ddd" },
    { 4, "eee" },  
};
1 aaa
2 ddd
3 bbb
4 eee
5 ccc
1. 默认排序规格

std标准库中带有less<>greater<>排序规则。

  • 指定less排序
map<int, string, less<int>> numAndPosMap{
    { 1, "aaa" },
    { 3, "bbb" },
    { 5, "ccc" },
    { 2, "ddd" },
    { 4, "eee" },  
};
1 aaa
2 ddd
3 bbb
4 eee
5 ccc
  • 指定greater排序
map<int, string, greater<int>> numAndPosMap{
    { 1, "aaa" },
    { 3, "bbb" },
    { 5, "ccc" },
    { 2, "ddd" },
    { 4, "eee" },  
};
5 ccc
4 eee
3 bbb
2 ddd
1 aaa
2. 修改按key排序规格

当key为自定义数据时,默认的排序规则就会失效,需要重写针对自定义数据的排序规则。

  • 在数据结构内重载比较运算符
struct MyKey {
    int num;
    string name;
    bool operator< (const MyKey& key) const
    {
        if (name < key.name) {
            return true;
        } else if (name > key.name) {
            return false;
        }

        return num < key.num;
    }
};
using KeyType = MyKey;

template<typename T>
void ShowVectorElem(T elems)
{   
    cout << "size: " << elems.size() << endl;
    for (const auto& elem : elems) {
        cout << elem.first.num << " " << elem.first.name << " " << elem.second << endl;
    }
}

int main() 
{
    map<KeyType, string, less<KeyType>> numAndPosMap{
        { { 1, "aaa" }, "ee"},
        { { 3, "bbb" }, "dd"},
        { { 5, "ccc" }, "cc"},
        { { 2, "ddd" }, "bb"},
        { { 4, "eee" }, "aa"},
    };

    ShowVectorElem(numAndPosMap);
    return 0;
}
1 aaa ee
3 bbb dd
5 ccc cc
2 ddd bb
4 eee aa
  • 重新写排序函数
struct MyKey {
    int num;
    string name;
};
using KeyType = MyKey;

ostream& operator<< (ostream& out, const MyKey& key)
{
    out << key.num << " - " << key.name;
    return out;
}

template<typename T>
void ShowVectorElem(T elems)
{   
    cout << "size: " << elems.size() << endl;
    for (const auto& elem : elems) {
        cout << elem.first << " " << elem.second << endl;
    }
}

int main() 
{
    auto cmp = [](const KeyType& a, const KeyType& b){
        if (a.name < b.name) {
            return true;
        } else if (a.name > b.name) {
            return false;
        }
        return a.num < b.num;
    };

    map<KeyType, string, decltype(cmp)> numAndPosMap(cmp);
    numAndPosMap.insert({ { 1, "aaa" }, "ee"});
    numAndPosMap.insert({ { 3, "bbb" }, "dd"});
    numAndPosMap.insert({ { 5, "ccc" }, "cc"});
    numAndPosMap.insert({ { 2, "ddd" }, "bb"});
    numAndPosMap.insert({ { 4, "eee" }, "aa"});

    ShowVectorElem(numAndPosMap);
    return 0;
}
size: 5
1 - aaa ee
3 - bbb dd
5 - ccc cc
2 - ddd bb
4 - eee aa
3. 修改按value排序规则

map没有随机迭代器,不能使用sort函数。如果需要对value排序,可以再建立一个以value为key的map(类似双映射)。
或者将map数据导入到可以使用sort的容器中,如vector中。

二、参考资料

STL map自定义排序

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
》灰《《常好的STL教程Effective STL 目录 容器 条款1: 仔细选择你要的容器 条款2: 小心对“容器无关代码”的幻想 条款3: 使容器里对象的拷贝操作轻量而正确 条款4: 用empty来代替检查size是否为0 条款5: 尽量使用范围成员函数代替他们的单元素兄弟 条款6: 警惕C++的及其令人恼怒的分析 条款7: 当使用new得指针的容器时,切记在容器销毁前delete那些指针 条款8: 千万不要把auto_ptr放入容器中 条款9: 小心选择删除选项 条款10: 当心allocator的协定和约束 条款11: 了解自定义allocator的正统使用法 条款12: 对STL容器的线程安全性的期待现实一些 vector和string 条款13: 尽量使用vector和string来代替动态申请的数组 条款14: 用reserve来避免不必要的内存重新分配 条款15: 当心string的实现中的变化 条款16: 如何将vector和string的数据传给传统的API 条款17: 用“交换技巧”来修正过度的容量 条款18: 避免使用vector 关联容器 条款19: 了解相等和等价的区别 条款20: 为包含指针的关联容器指定比较类型 条款21: 永远让比较函数对相等的值返回false 条款22: 避免对set和multiset的键值进行修改 条款23: 考虑用排序的vector代替关联容器 条款24: 当效率很关键时尽量用map::insert代替map::operator 条款25: 让自己熟悉非标准的hash容器 迭代器 条款26: 尽量使用iterator代替const_iterator,reverse_iterator和const_reverse_iterator 条款27: 使用distance和advance把const_iterators转化成iterators 条款28: 了解如何通过reverse_iterator的base得到iterator 条款29: 需要一字符一字符输入时请用istreambuf_iterator 算法 条款30: 确保目的范围足够大 条款31: 了解你的排序选项 条款32: 如果你真的想删除东西的话在remove-like的算法后紧接上erase 条款33: 当心在包含指针的容器使用remove-like的算法 条款34: 注意哪些算法需要排序过的范围 条款35: 通过mismatch或lexicographical_compare实现简单的忽略大小写字符串比较 条款36: 用not1和remove_copy_if来表现copy_if 条款37: 用accumulate或for_each来统计序列 仿函数,仿函数类,函数等等 条款38: 把仿函数类设计成值传递的 条款39: 用纯函数做predicate 条款40: 增强仿函数类的适应性 条款41: 明确ptr_fun, mem_fun和mem_fun_ref的区别 条款42: 保证less是operator<的意思 用STL编程 条款43: 尽量用算法调用代替手写循环 条款44: 尽量用成员函数代替同名的算法 条款45: 注意count、find、binary_search、lower_bound、upper_bound和equal_range的区别 条款46: 考虑用函数对象代替函数作为算法的参数 条款47: 避免产生只写代码 条款48: 总是#include适当的头文件 条款49: 学会破解STL相关的编译器出错信息 条款50: 让自己熟悉STL相关的网站
目录 1 前面的话 1 1.1 历史 1 1.2 内容 1 1.3 基础知识 1 1.4 三种境界 1 1.5 STL特点 1 1.6 资源 1 1.7 学习方法 1 2 语言特性 3 2.1 模板 3 2.2 typename 3 2.3 模板类的拷贝构造函数 3 2.4 基本类型数据初始化 3 2.5 异常处理 4 2.6 命名空间 4 2.7 using声明 4 2.8 namespace std 4 2.9 explicit关键字 5 2.10 新的类型转换符 5 2.11 静态常量成员的初始化 6 2.12 时间复杂度O记号 6 3 一般概念 7 3.1 头文件 7 3.2 错误处理和异常处理 7 3.2.1 异常头文件 7 3.2.2 标准异常分类 7 3.2.3 异常规格 8 3.2.4 如何在程序中找出异常类型 8 3.2.5 抛出标准异常和实现自己的异常 8 3.3 配置器 8 4 通用工具 9 4.1 简介 9 4.1.1 类别 9 4.1.2 头文件 9 4.2 Pairs 9 4.2.1 简介 9 4.2.2 示例 9 4.3 auto_ptr 10 4.3.1 作用 10 4.3.2 引入原因 10 4.3.3 声明 10 4.3.4 auto_ptr拥有权的转移 10 4.3.5 示例 11 4.3.6 用途 12 4.4 数值极限 13 4.4.1 引入原因 13 4.4.2 头文件 13 4.4.3 numeric_limits<> 13 4.5 辅助函数 14 4.5.1 max、min 14 4.5.2 swap 15 4.6 头文件<cstddef>、<cstdlib> 15 4.6.1 <cstddef> 15 4.6.2 <cstdlib> 15 5 STL标准程序库 16 5.1 STL组件 16 5.1.1 分类 16 5.1.2 基本观念 16 5.1.3 好处 16 5.2 容器(containers) 16 5.2.1 分类 16 5.2.2 序列式容器示例 16 5.2.3 关联式容器 18 5.3 迭代器 18 5.3.1 示例 19 5.3.2 迭代器分类 21 5.4 算法 21 5.4.1 区间 22 5.4.2 处理多个区间 22 5.5 迭代器的配接器 24 5.5.1 种类 24 5.5.2 Insert Insertors 24 5.5.3 Stream Iterator 25 5.5.4 reverse iterator 25 5.6 变动型算法 26 5.6.1 删除元素 26 5.6.2 变动型算法和关联式容器 27 5.6.3 算法vs.成员函数 28 5.7 使用者自定义的泛型函数 29 5.8 以函数作为算法的参数 29 5.8.1 示例for_each和transform 29 5.8.2 判断式(predicates) 30 5.9 仿函数 33 5.9.1 什么是仿函数 33 5.9.2 预先定义的仿函数 35 5.10 容器内的元素<class T> 36 5.10.1 容器元素的条件 36 5.10.2 value和reference 37 5.11 STL内部的错误处理和异常处理 37 5.11.1 错误处理(Error Handling) 37 5.11.2 异常处理 38 5.12 扩展STL 38 6 STL容器 39 6.1 容器的共同能力 39 6.2 vector 39 6.2.1 vector的能力 39 6.2.2 vector实例 40 6.3 deque 41 6.3.1 Deque的能力 41 6.3.2 Deque的使用时机 41 6.3.3 示例 41 6.4 List 42 6.4.1 list的能力 42 6.4.2 list的操作函数 42 6.4.3 splice函数 43 6.4.4 示例 43 6.5 set和multiset 44 6.5.1 示例 44 6.5.2 set和multiset举例 46 6.6 map和multimap 49 6.6.1 map和multimap的能力 50 6.6.2 将map视为关联式数组 52 6.6.3 map和multimap运用示例 52 6.6.4 综合示例 55 6.7 其它STL容器 57 6.7.1 HashTable 59 6.7.2 引用计数 59 6.8 各种容器的运用时机 61 6.8.1 各种容器的使用时机 61 7 STL迭代器 64 7.1 迭代器头文件 64 7.2 迭代器类型 64 7.2.1 Input迭代器 64 7.2.2 Output迭代器 64 7.2.3 Forward迭代器 65 7.2.4 双向迭代器 65 7.2.5 随机存取迭代器 65 7.2.6 Vector迭代器的递增和递减 67 7.3 迭代器辅助函数 67 7.3.1 advance()可令迭代器前进 67 7.3.2 distance()可处理迭代器之间的距离 68 7.3.3 iter_swap()交换两个迭代器所指内容 68 7.4 迭代器配接器(adapter) 69 7.4.1 逆向迭代器 69 7.4.2 Insert迭代器 72 7.4.3 Stream迭代器 75 7.5 迭代器特性 76 8 STL仿函数 77 8.1 仿函数概念 77 8.1.1 仿函数当做排序准则 77 8.1.2 拥有内部状态的仿函数 78 8.1.3 for_each()的返回值 80 8.1.4 判断式和仿函数 81 8.2 预定义的仿函数 82 8.2.1 函数配接器 82 8.2.2 针对成员函数而设计的函数配接器 83 9 STL算法 85 9.1 算法头文件 85 9.2 算法概览 85 9.2.1 简介 85 9.2.2 算法分类 85 9.3 辅助函数 85 9.4 for_each()算法 86 9.5 非变动性算法 88 9.5.1 元素计数 88 9.5.2 最小值和最大值 88 9.5.3 搜寻元素 89 9.5.4 区间的比较 95 9.6 变动性算法 98 9.6.1 复制元素 98 9.6.2 转换和结合元素 99 9.6.3 互换元素内容 101 9.6.4 赋予新值 101 9.6.5 替换元素 103 9.7 移除性算法 104 9.7.1 移除某些特定元素 104 9.7.2 移除重复元素 105 9.8 变序性算法 107 9.8.1 逆转元素次序 107 9.8.2 旋转元素次序 107 9.8.3 排列元素 109 9.8.4 重排元素 109 9.8.5 将元素向前搬移 110 9.9 排序算法 111 9.9.1 对所有元素排序 111 9.9.2 局部排序 112 9.9.3 根据第n个元素排序 113 9.9.4 heap算法 114 9.10 已序区间算法 115 9.10.1 搜寻元素 115 9.10.2 合并元素 117 9.11 数值算法 120 9.11.1 加工运算后产生结果 120 9.11.2 相对值和绝对值之间的转换 121 10 特殊容器 123 10.1 Stacks 123 10.1.1 核心接口 123 10.1.2 Stack运用实例 123 10.1.3 使用自定义的Stack类 124 10.2 Queue 125 10.2.1 核心接口 126 10.2.2 Queue运用实例 126 10.2.3 使用者自定义的队列 126 10.3 Priority Queue 128 10.3.1 核心接口 128 10.3.2 运用实例 128 10.4 Bitset 129 10.4.1 Bitset运用实例 129 11 Strings 131 11.1 动机 131 11.1.1 示例:引出一个临时文件名 131 11.1.2 例二:引出一段文字并逆向打印 132 11.2 未提供的操作函数 132 11.2.1 大小和容量 132 12 数值 135 12.1 复数 135 12.2 valarray 136 12.2.1 认识valarray 136 12.2.2 valarray的子集 138 13 以stream classes完成输入/输出 143 13.1.1 示例 143 13.2 基本的Stream类别和Stream对象 144 13.3 文件存取 144 13.3.1 重定向 147 13.3.2 用于读写的Stream 147 13.4 String Stream class 148 13.4.1 Stream缓冲区迭代器示例 14 国际化 150149 15 空间配置器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值