C++ STL关联式容器自定义排序规则(2种方法)
前面在讲解如何创建 map、multimap、set 以及 multiset 容器时,遗留了一个问题,即如何自定义关联式容器中的排序规则?总的来说,为关联式容器自定义排序规则,有以下 2 种方法。 1) 使用函数对象自定义排序规则无论关联式容器中存储的是基础类型(如 int、double、float 等)数据,还是自定义的结构体变量或类对象(包括 string 类),都可以使用函数对象的方式为该容器自定义排序规则。 下面样例以 set 容器为例,演示了如何用函数对象的方式自定义排序规则: #include <iostream> #include <set> // set #include <string> // string using namespace std; //定义函数对象类 class cmp { public: //重载 () 运算符 bool operator ()(const string &a,const string &b) { //按照字符串的长度,做升序排序(即存储的字符串从短到长) return (a.length() < b.length()); } }; int main() { //创建 set 容器,并使用自定义的 cmp 排序规则 std::set<string,cmp>myset{"http://c.biancheng.net/stl/","http://c.biancheng.net/python/","http://c.biancheng.net/java/"}; //输出容器中存储的元素 for (auto iter = myset.begin(); iter != myset.end(); ++iter) { cout << *iter << endl; } return 0; }程序执行结果为:
http://c.biancheng.net/stl/ 另外,C++ 中的 struct 和 class 非常类似(有关两者区别,可阅读《C++ struct和class到底有什么区别》一文),前者也可以包含成员变量和成员函数。因此上面程序中,函数对象类 cmp 也可以使用 struct 关键字创建: //定义函数对象类 struct cmp { //重载 () 运算符 bool operator ()(const string &a,const string &b) { //按照字符串的长度,做升序排序(即存储的字符串从短到长) return (a.length() < b.length()); } };值得一提的是,在定义函数对象类时,也可以将其定义为模板类。比如: //定义函数对象模板类 template <typename T> class cmp { public: //重载 () 运算符 bool operator ()(const T &a,const T &b) { //按照值的大小,做升序排序 return a < b; } };
2) 重载关系运算符实现自定义排序其实在 STL 标准库中,本就包含几个可供关联式容器使用的排序规则,如表 1 表示。
值得一提的是,表 1 中的这些排序规则,其底层也是采用函数对象的方式实现的。以 std::less<T> 为例,其底层实现为: template <typename T> struct less { //定义新的排序规则 bool operator()(const T &_lhs,const T &_rhs) const { return _lhs < _rhs; } }在此基础上,当关联式容器中存储的数据类型为自定义的结构体变量或者类对象时,通过对现有排序规则中所用的关系运算符进行重载,也能实现自定义排序规则的目的。 举个例子: #include <iostream> #include <set> // set #include <string> // string using namespace std; //自定义类 class myString { public: //定义构造函数,向 myset 容器中添加元素时会用到 myString(string tempStr) :str(tempStr) {}; //获取 str 私有对象,由于会被私有对象调用,因此该成员方法也必须为 const 类型 string getStr() const; private: string str; }; string myString::getStr() const{ return this->str; } //重载 < 运算符,参数必须都为 const 类型 bool operator <(const myString &stra,const myString & strb) { //以字符串的长度为标准比较大小 return stra.getStr().length() < strb.getStr().length(); } int main() { //创建空 set 容器,仍使用默认的 less<T> 排序规则 std::set<myString>myset; //向 set 容器添加元素,这里会调用 myString 类的构造函数 myset.emplace("http://c.biancheng.net/stl/"); myset.emplace("http://c.biancheng.net/c/"); myset.emplace("http://c.biancheng.net/python/"); // for (auto iter = myset.begin(); iter != myset.end(); ++iter) { myString mystr = *iter; cout << mystr.getStr() << endl; } return 0; }程序执行结果为:
http://c.biancheng.net/c/ 另外,上面程序以全局函数的形式实现对 < 运算符的重载,还可以使用成员函数或者友元函数的形式实现。其中,当以成员函数的方式重载 < 运算符时,该成员函数必须声明为 const 类型,且参数也必须为 const 类型: bool operator <(const myString & tempStr) const { //以字符串的长度为标准比较大小 return this->str.length() < tempStr.str.length(); } 同样,如果以友元函数的方式重载 < 运算符时,要求参数必须使用 const 修饰: //类中友元函数的定义 friend bool operator <(const myString &a,const myString &b); //类外部友元函数的具体实现 bool operator <(const myString &stra,const myString &strb) { //以字符串的长度为标准比较大小 return stra.str.length() < strb.str.length(); }
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |