C++ STL关联式容器自定义排序规则的2种方法
前面在讲解如何创建map、multimap、set以及multiset容器时,遗留了一个问题,即如何自定义关联式容器中的排序规则?
实际上,为关联式容器自定义排序规则的方法,已经在《STLpriority_queue自定义排序方法》一节中做了详细的讲解。换句话说,为Priority_queue容器适配器自定义排序规则的方法,同样适用于所有关联式容器。
总的来说,为关联式容器自定义排序规则,有以下2种方法。
1)使用函数对象自定义排序规则
在掌握此方法之前,读者必须对函数对象有基本的了解,可阅读《C++函数对象》一节。
无论关联式容器中存储的是基础类型(如int、double、float等)数据,还是自定义的结构体变量或类对象(包括string类),都可以使用函数对象的方式为该容器自定义排序规则。
下面样例以set容器为例,演示了如何用函数对象的方式自定义排序规则:
#include#include //set #include //string usingnamespacestd; //定义函数对象类 classcmp{ public: //重载()运算符 booloperator()(conststring&a,conststring&b){ //按照字符串的长度,做升序排序(即存储的字符串从短到长) return(a.length() myset{"http://jb51.net.net/stl/", "http://jb51.net.net/python/", "http://jb51.net.net/java/"}; //输出容器中存储的元素 for(autoiter=myset.begin();iter!=myset.end();++iter){ cout<<*iter< 程序执行结果为:
http://jb51.net.net/stl/
http://jb51.net.net/java/
http://jb51.net.net/python/重点分析一下6~13行代码,其定义了一个函数对象类,并在其重载()运算符的方法中自定义了新的排序规则,即按照字符串的长度做升序排序。在此基础上,程序第17行代码中,通过将函数对象类的类名cmp通过set类模板的第2个参数传递给myset容器,该容器内部排序数据的规则,就改为了以字符串的长度为标准做升序排序。
需要注意的是,此程序中创建的myset容器,由于是以字符串的长度为准进行排序,因此其无法存储相同长度的多个字符串。另外,C++中的struct和class非常类似(有关两者区别,可阅读《C++struct和class到底有什么区别》一文),前者也可以包含成员变量和成员函数。因此上面程序中,函数对象类cmp也可以使用struct关键字创建:
//定义函数对象类 structcmp{ //重载()运算符 booloperator()(conststring&a,conststring&b){ //按照字符串的长度,做升序排序(即存储的字符串从短到长) return(a.length()值得一提的是,在定义函数对象类时,也可以将其定义为模板类。比如:
//定义函数对象模板类 templateclasscmp{ public: //重载()运算符 booloperator()(constT&a,constT&b){ //按照值的大小,做升序排序 returna 注意,此方式必须保证T类型元素可以直接使用关系运算符(比如这里的<运算符)做比较。
2)重载关系运算符实现自定义排序
其实在STL标准库中,本就包含几个可供关联式容器使用的排序规则,如表1表示。
表1C++STL标准库适用于关联式容器的排序规则
排序规则 功能 std::less 底层采用<运算符实现升序排序,各关联式容器默认采用的排序规则。 std::greater 底层采用>运算符实现降序排序,同样适用于各个关联式容器。 std::less_equal 底层采用<=运算符实现升序排序,多用于multimap和multiset容器。 std::greater_equal 底层采用>=运算符实现降序排序,多用于multimap和multiset容器。 值得一提的是,表1中的这些排序规则,其底层也是采用函数对象的方式实现的。以std::less
为例,其底层实现为:
templatestructless{ //定义新的排序规则 booloperator()(constT&_lhs,constT&_rhs)const{ return_lhs<_rhs; } } 在此基础上,当关联式容器中存储的数据类型为自定义的结构体变量或者类对象时,通过对现有排序规则中所用的关系运算符进行重载,也能实现自定义排序规则的目的。
注意,当关联式容器中存储的元素类型为结构体指针变量或者类的指针对象时,只能使用函数对象的方式自定义排序规则,此方法不再适用。
举个例子:
#include#include //set #include //string usingnamespacestd; //自定义类 classmyString{ public: //定义构造函数,向myset容器中添加元素时会用到 myString(stringtempStr):str(tempStr){}; //获取str私有对象,由于会被私有对象调用,因此该成员方法也必须为const类型 stringgetStr()const; private: stringstr; }; stringmyString::getStr()const{ returnthis->str; } //重载<运算符,参数必须都为const类型 booloperator<(constmyString&stra,constmyString&strb){ //以字符串的长度为标准比较大小 returnstra.getStr().length() 排序规则 std::set myset; //向set容器添加元素,这里会调用myString类的构造函数 myset.emplace("http://jb51.net.net/stl/"); myset.emplace("http://jb51.net.net/c/"); myset.emplace("http://jb51.net.net/python/"); // for(autoiter=myset.begin();iter!=myset.end();++iter){ myStringmystr=*iter; cout< 程序执行结果为:
http://jb51.net.net/c/
http://jb51.net.net/stl/
http://jb51.net.net/python/在这个程序中,虽然myset容器表面仍采用默认的std::less
排序规则,但由于我们对其所用的<运算符进行了重载,使得myset容器内部实则是以字符串的长度为基准,对各个mystring类对象进行排序。 另外,上面程序以全局函数的形式实现对<运算符的重载,还可以使用成员函数或者友元函数的形式实现。其中,当以成员函数的方式重载<运算符时,该成员函数必须声明为const类型,且参数也必须为const类型:
booloperator<(constmyString&tempStr)const{ //以字符串的长度为标准比较大小 returnthis->str.length()至于参数的传值方式是采用按引用传递还是按值传递,都可以(建议采用按引用传递,效率更高)。
同样,如果以友元函数的方式重载<运算符时,要求参数必须使用const修饰:
//类中友元函数的定义 friendbooloperator<(constmyString&a,constmyString&b); //类外部友元函数的具体实现 booloperator<(constmyString&stra,constmyString&strb){ //以字符串的长度为标准比较大小 returnstra.str.length()当然,本节所讲自定义排序规则的方法并不仅仅适用于set容器,其它关联式容器(map、multimap、multiset)也同样适用,有兴趣的读者可自行编写代码验证。
到此这篇关于C++STL关联式容器自定义排序规则的2种方法的文章就介绍到这了,更多相关C++STL关联式容器自定义排序内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!