STL的容器map为我们处理有序key-value形式数据提供了非常大的便利,由于内部红黑树结构的存储,查找的时间复杂度为O(log2N)。

一般而言,使用map的时候直接采取map<typename A, typename B>的形式即可,map的内部实现默认使用A类型变量的升序来排序map的值。

但是有时我们需要对map的值做特殊的排序(不经其他容器的辅助),这就需要在定义map变量时做些特殊的处理。

STL中map的定义是:

 template<class _Kty,
class _Ty,
class _Pr = less<_Kty>,
class _Alloc = allocator<pair<const _Kty, _Ty>>>
class map
: public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>>
{

这是一个模板类,我们的特殊处理主要改造的就是class _Pr = less<_Kty>,并且从这里我们也能看到,无论做哪种修改,排序都是针对key而言的,要实现value的自定义排序,

不是修改_Pr类型能完成的。

替换_Pr的也必须是一个类型,即至少我们要自己创建一个类型,用来做key的比较。自然,我们需要做的是重载函数调用操作符"()",一般的形式为

 class T{
public:
bool operator()(const T& lhs, const T& rhs)const
{
...
}
};

代码需包含头文件<algorithm>、<functional>。

下面是常见的一些自定义排序:

a.对基本类型的key以降序排列

  map默认提供的是less<_Kty>类型的排序方式,阅读STL源码

 template<class _Ty = void>
struct less
{ // functor for operator<
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type; constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};

  修改上述代码的第10行,为修改后的类型起一个自定义名字很简单,不过STL已经为我们提供了整个类型定义:

 template<class _Ty = void>
struct greater
{ // functor for operator>
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type; constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator> to operands
return (_Left > _Right);
}
};

  我们直接使用就行:

 std::map<int, int, std::greater<int>> mi;
for (int i = ; i < ; i++)
{
mi[i] = i * ;
} std::for_each(mi.begin(), mi.end(),
[](const std::map<int, int, std::greater<int>>::value_type& vl) {
cout << "key:" << vl.first << "  value:" << vl.second << '\n';
});

  对应的输出为:

  

  这里,我们实现了按key降序排列的目的。

b.为自定义类型的key做排序:

  自定义类型的key定义map时(使用map默认排序),我们一般都要做一件事:为自定义类型重载“<”操作符,显然,这是为了map创建对象时可以使用less。

  因此,我们替换less<_Kty>也同样是要做这样的事:自定义排序规则,  比如:

 class MyKey {
public:
MyKey(int fidx = , int sidx = )
:m_firstIdx(fidx), m_secondIdx(sidx) {} int m_firstIdx;
int m_secondIdx;
}; class MyCompare{
public:
bool operator()(const MyKey& lhs, const MyKey& rhs)const
{
if (lhs.m_firstIdx > rhs.m_firstIdx)
{
return true;
}
else if (lhs.m_firstIdx == rhs.m_firstIdx)
{
return lhs.m_secondIdx > rhs.m_secondIdx;
}
return false;
}
}; class MyCompare2 {
public:
bool operator()(const MyKey& lhs, const MyKey& rhs)const
{
return lhs.m_firstIdx > rhs.m_firstIdx;
}
};

使用MyCompare:

 std::map<MyKey, int, MyCompare> mi;
for (int i = ; i < ; i++)
{
mi[MyKey(i * , i)] = i * ;
} std::for_each(mi.begin(), mi.end(),
[](const std::map<MyKey, int, MyCompare>::value_type& vl) {
cout << "key:" << vl.first.m_firstIdx << "-" << vl.first.m_secondIdx << " value:" << vl.second << '\n';
});

使用MyCompare2:

 std::map<MyKey, int, MyCompare2> mi;
for (int i = ; i < ; i++)
{
mi[MyKey(i * , i)] = i * ;
} std::for_each(mi.begin(), mi.end(),
[](const std::map<MyKey, int, MyCompare2>::value_type& vl) {
cout << "key:" << vl.first.m_firstIdx << "-" << vl.first.m_secondIdx << " value:" << vl.second << '\n';
});

  以上两种有相同的输出:

我们实现了自定义类型自定义排序的目的。

可以看到,使用map其实有很大的自由度,我们完全可以定制自己的map,为我们解决问题、精简代码带来很大的便利。

  

map的默认排序和自定义排序的更多相关文章

  1. MySQL、Oracle、DB2等数据库常规排序、自定义排序和按中文拼音字母排序

    MySQL常规排序.自定义排序和按中文拼音字母排序,在实际的SQL编写时,我们有时候需要对条件集合进行排序. 下面给出3中比较常用的排序方式,mark一下 1.常规排序ASC DESC ASC 正序 ...

  2. Objective-C之NSArray(数组)默认排序与自定义排序

    在讲OC中数组的排序之前我先上一段代码,它是简单数组排序的一种方法(也就是元素是字符串或者数据的数组,因为后面要讲元素为类的数组排序) 代码1: NSArray *sortArr4 = [sortAr ...

  3. EasyUI 数据网格 - 设置排序并自定义排序

    数据网格(DataGrid)的所有列可以通过点击列表头来排序.您可以定义哪列可以排序.默认的,列是不能排序的,除非您设置 sortable 属性为 true. 当排序时,数据网格(DataGrid)将 ...

  4. mysql排序的中文首字母排序和自定义排序

    select * FROM organ_new where city_code = 'SZ0755' and organ_type = 'H' and state = '1' ORDER BY FIE ...

  5. hdu 1263 水果 结构的排序+sort自定义排序

    水果 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...

  6. Map排序——按key排序,按value排序

    注:转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/5959279.html 上一篇博文谈到了集合类的自定义排序方式,那么进一步扩展开来,与集合同等重要的Map有 ...

  7. MySQL中自定义排序

    在开发时候,我们经常使用的是默认的排序规则,但在某些特殊情况下,通过指定顺序来进行排序 -- fileld自定义排序时,应该是非主键的,否则主键是无效 SELECT * FROM customer W ...

  8. Python自定义排序及我实际遇到的一些题目实例

    写在前面,本文主要介绍Python基础排序和自定义排序的一些规则,如果都比较熟悉,可以直接翻到第三节,看下实际的笔试面试题中关于自定义排序的应用. 一.基础排序 排序是比较基础的算法,与很多语言一样, ...

  9. Python:Base4(map,reduce,filter,自定义排序函数(sorted),返回函数,闭包,匿名函数(lambda) )

    1.python把函数作为参数: 在2.1小节中,我们讲了高阶函数的概念,并编写了一个简单的高阶函数: def add(x, y, f): return f(x) + f(y) 如果传入abs作为参数 ...

随机推荐

  1. JavaScript入门学习(1)

    <html> <script type ="text/javascript"> var i,j; for (i=1;i<10;i++){ for (j ...

  2. 嵌入式C语言自我修养 04:Linux 内核第一宏:container_of

    4.1 typeof 关键字 ANSI C 定义了 sizeof 关键字,用来获取一个变量或数据类型在内存中所占的存储字节数.GNU C 扩展了一个关键字 typeof,用来获取一个变量或表达式的类型 ...

  3. Zeta--S3 Linux使用PCCAM/WEBCAM模式

    #include <ZetaCameraInterface.h> #include <ZetaMediaPlayInterface.h> using namespace zet ...

  4. Angular Elements

    Angular Elements Angular Elements 就是打包成自定义元素的 Angular 组件.所谓自定义元素就是一套与具体框架无关的用于定义新 HTML 元素的 Web 标准. 自 ...

  5. 20155233 2006-2007-2 《Java程序设计》第4周学习总结

    20155233 2006-2007-2 <Java程序设计>第4周学习总结 教材学习内容总结 第六章: 继承:子类继承父类,避免重复的行为定义. extends关键词:继承并扩充行为. ...

  6. linux IPC机制学习博客

    要求 研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接 - 共享内存 - 管道 - FIFO - 信号 - 消息队列 研究博客 管道(PIPE) 管道(PIPE): ...

  7. 20155338 2016-2017-2 《Java程序设计》第3周学习总结

    20155338 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 本周学习量比较多,但是知识点并不是特别难,学习了书本的第四五章,其中个人重点学习了数组对象. ...

  8. python 多线程笔记(5)-- 生产者/消费者模式

    我们已经知道,对公共资源进行互斥访问,可以使用Lock上锁,或者使用RLock去重入锁. 但是这些都只是方便于处理简单的同步现象,我们甚至还不能很合理的去解决使用Lock锁带来的死锁问题. 要解决更复 ...

  9. 【LG3243】[HNOI2015]菜肴制作

    题面 洛谷 题解 首先我们有个非常显然的思路, 就是直接拓扑排序,用小根堆代替队列再按顺序输出,但是很显然是错的, 因为这只保证了字典序最小,而无法保证答案最优,\(<2,4>,<3 ...

  10. 2288: 【POJ Challenge】生日礼物

    2288: [POJ Challenge]生日礼物 https://lydsy.com/JudgeOnline/problem.php?id=2288 分析: 贪心+堆+链表. 首先把序列变一下,把相 ...