第一节 常见容器自定义比较函数示例
容器的排序:容器的使用过程中,经常涉及到排序,对于比较函数的定义如果大家没有使用过,就会问,需要自己定义吗?怎么定义?有没有现成的?哪些容器需要?等等。本文主要帮助大家解决此疑惑,一方面是总结,一方面是教大家如何通过源码来找到定义。
容器的分类:
序列式容器(随机迭代器):vector, list, deque
关联式容器(非随机迭代器):set, map, multiset, multimap
配置器容器(不提供迭代器):queue, stack, priority_queue
关联式容器一直保持有序的状态,并且不支持随机迭代,因此需要初始化比较函数,一般容器会提供默认比较函数,通常小值在前。
序列式容器元素不是必须保持有序的,当需要元素有序时,可以通过sort、stabel_sort等排序算法来实现排序。
配置器容器是某种容器的变种,它提供原容器的一个专用受限接口,并且不提供迭代器,其中 priority_queue是有序容器。
综上,我们将容器分成两类,一类需要初始化排序函数的(set, map,priority_queue),一类可以使用sort排序的(vector, list, deque)。
具体的定义和使用请看代码,非常简单,此小节不详细介绍了。
#include #include #include #include #include #include #include #include /*第一类 比较函数1,用于比较基本类型*/using namespace std;templatestruct cmp1 {bool operator ()(const _Ty& _Left, const _Ty& _Right) const {return _Left > _Right;}};/*第一类 比较函数2,比较结构体*/struct Point{int x;int y;};class cmp2 {public:bool operator ()(const Point& _Left, const Point& _Right) const {return _Left.x > _Right.x;}};/*第二类 比较函数1*/bool cmp3(int& a, int& b) {return a < b;}int main(){/*set的使用示例*/set> s1;s1.insert({ 0,1,2,3 });printf("%d",*s1.begin());set s2;s2.insert({ {0,1},{2, 3},{3,4} });printf("%d", *s2.begin());/*优先队列的使用示例*/vector v = { 1,3,0,2 };priority_queue, cmp1> pq1(v.begin(),v.end());printf("%d", pq1.top());/*vector使用示例*/sort(v.begin(), v.end(), cmp3);printf("%d", v[0]);system("pause");return 0;}
第二节 从源码看定义
此小节我们以set为例,如果大家有兴趣,稍微花点时间,看下如何通过源码分析,来找到比较函数的定义。
类定义:set是个模板类,_Kty是数据类型(必传),_Pr是比较类(本文核心),_Allocs是内存分配器(本文不展开)。类定义如下,继承了_Tree
![d2d5944cd783cf0497a3d8681f28017a.png](https://i-blog.csdnimg.cn/blog_migrate/c615436a8223275b062520f1ce0fa554.jpeg)
set的定义
构造函数:set的默认构造函数会初始化调用父类_Mybase的构造函数,入参为key_compare,即模板类_Pr 比较函数
![6346866be8feda81cb9b908aa2b848b8.png](https://i-blog.csdnimg.cn/blog_migrate/3c1a800efb6b5ec3b312f79a5d4da8ca.jpeg)
模板类_Pr的类型别名
![6f4c242804ac7052c81ab258351069f6.png](https://i-blog.csdnimg.cn/blog_migrate/3988dce68aed932caa869256d5cb20ba.jpeg)
set的默认构造函数
比较函数:跟踪key_compare定义,可以看到比较函数的定义如下,里面重载了小括号运算符,key_compare() 返回一个比较函数,入参是_Left和_Right的引用,小值排在前面:
![7a8cff6163cc6b5031db879fc12cc2dd.png](https://i-blog.csdnimg.cn/blog_migrate/e46d437d80550151d7e246618ff9c93c.jpeg)
set的默认比较函数
比较函数作用的时间点:跟踪insert操作代码,发现比较函数最终是通过一个宏定义来调用的,其中Pred即比较函数。
![102e17ea2e3f19d463d08073f1fea67a.png](https://i-blog.csdnimg.cn/blog_migrate/a7283bc7ea5a2643e0821ba216c3d49d.jpeg)
比较函数的宏定义
查看此宏的定义,发现比较函数只需要满足两个同类型入参,返回值能转换成bool类型即可。
![94cec2e4bf6ee02ddeb96a90fb64895b.png](https://i-blog.csdnimg.cn/blog_migrate/7667fb88a64675a31d44073f02d28cec.jpeg)
比较函数的宏定义
第三节 总结
STL容器是我们经常需要使用到的,在Leetcode刷题时,时常会碰到一时想不起来如何定义比较函数的,因此我们要知其然知其所以然,能够单独推导出相关的定义,避免陷入背公式的泥潭中。