C++ STL關(guān)聯(lián)式容器自定義排序規(guī)則的2種方法
前面在講解如何創(chuàng)建 map、multimap、set 以及 multiset 容器時(shí),遺留了一個(gè)問題,即如何自定義關(guān)聯(lián)式容器中的排序規(guī)則?
實(shí)際上,為關(guān)聯(lián)式容器自定義排序規(guī)則的方法,已經(jīng)在 《STL priority_queue自定義排序方法》一節(jié)中做了詳細(xì)的講解。換句話說,為 Priority_queue 容器適配器自定義排序規(guī)則的方法,同樣適用于所有關(guān)聯(lián)式容器。
總的來說,為關(guān)聯(lián)式容器自定義排序規(guī)則,有以下 2 種方法。
1) 使用函數(shù)對象自定義排序規(guī)則
在掌握此方法之前,讀者必須對函數(shù)對象有基本的了解,可閱讀《C++函數(shù)對象》一節(jié)。
無論關(guān)聯(lián)式容器中存儲(chǔ)的是基礎(chǔ)類型(如 int、double、float 等)數(shù)據(jù),還是自定義的結(jié)構(gòu)體變量或類對象(包括 string 類),都可以使用函數(shù)對象的方式為該容器自定義排序規(guī)則。
下面樣例以 set 容器為例,演示了如何用函數(shù)對象的方式自定義排序規(guī)則:
#include <iostream> #include <set> // set #include <string> // string using namespace std; //定義函數(shù)對象類 class cmp { public: //重載 () 運(yùn)算符 bool operator ()(const string &a,const string &b) { //按照字符串的長度,做升序排序(即存儲(chǔ)的字符串從短到長) return (a.length() < b.length()); } }; int main() { //創(chuàng)建 set 容器,并使用自定義的 cmp 排序規(guī)則 std::set<string, cmp>myset{"http://jb51.net.net/stl/", "http://jb51.net.net/python/", "http://jb51.net.net/java/"}; //輸出容器中存儲(chǔ)的元素 for (auto iter = myset.begin(); iter != myset.end(); ++iter) { cout << *iter << endl; } return 0; }
程序執(zhí)行結(jié)果為:
http://jb51.net.net/stl/
http://jb51.net.net/java/
http://jb51.net.net/python/
重點(diǎn)分析一下 6~13 行代碼,其定義了一個(gè)函數(shù)對象類,并在其重載 () 運(yùn)算符的方法中自定義了新的排序規(guī)則,即按照字符串的長度做升序排序。在此基礎(chǔ)上,程序第 17 行代碼中,通過將函數(shù)對象類的類名 cmp 通過 set 類模板的第 2 個(gè)參數(shù)傳遞給 myset 容器,該容器內(nèi)部排序數(shù)據(jù)的規(guī)則,就改為了以字符串的長度為標(biāo)準(zhǔn)做升序排序。
需要注意的是,此程序中創(chuàng)建的 myset 容器,由于是以字符串的長度為準(zhǔn)進(jìn)行排序,因此其無法存儲(chǔ)相同長度的多個(gè)字符串。
另外,C++ 中的 struct 和 class 非常類似(有關(guān)兩者區(qū)別,可閱讀《C++ struct和class到底有什么區(qū)別》一文),前者也可以包含成員變量和成員函數(shù)。因此上面程序中,函數(shù)對象類 cmp 也可以使用 struct 關(guān)鍵字創(chuàng)建:
//定義函數(shù)對象類 struct cmp { //重載 () 運(yùn)算符 bool operator ()(const string &a, const string &b) { //按照字符串的長度,做升序排序(即存儲(chǔ)的字符串從短到長) return (a.length() < b.length()); } };
值得一提的是,在定義函數(shù)對象類時(shí),也可以將其定義為模板類。比如:
//定義函數(shù)對象模板類 template <typename T> class cmp { public: //重載 () 運(yùn)算符 bool operator ()(const T &a, const T &b) { //按照值的大小,做升序排序 return a < b; } };
注意,此方式必須保證 T 類型元素可以直接使用關(guān)系運(yùn)算符(比如這里的 < 運(yùn)算符)做比較。
2) 重載關(guān)系運(yùn)算符實(shí)現(xiàn)自定義排序
其實(shí)在 STL 標(biāo)準(zhǔn)庫中,本就包含幾個(gè)可供關(guān)聯(lián)式容器使用的排序規(guī)則,如表 1 表示。
表 1 C++ STL標(biāo)準(zhǔn)庫適用于關(guān)聯(lián)式容器的排序規(guī)則
排序規(guī)則 | 功能 |
---|---|
std::less<T> | 底層采用 < 運(yùn)算符實(shí)現(xiàn)升序排序,各關(guān)聯(lián)式容器默認(rèn)采用的排序規(guī)則。 |
std::greater<T> | 底層采用 > 運(yùn)算符實(shí)現(xiàn)降序排序,同樣適用于各個(gè)關(guān)聯(lián)式容器。 |
std::less_equal<T> | 底層采用 <= 運(yùn)算符實(shí)現(xiàn)升序排序,多用于 multimap 和 multiset 容器。 |
std::greater_equal<T> | 底層采用 >= 運(yùn)算符實(shí)現(xiàn)降序排序,多用于 multimap 和 multiset 容器。 |
值得一提的是,表 1 中的這些排序規(guī)則,其底層也是采用函數(shù)對象的方式實(shí)現(xiàn)的。以 std::less<T> 為例,其底層實(shí)現(xiàn)為:
template <typename T> struct less { //定義新的排序規(guī)則 bool operator()(const T &_lhs, const T &_rhs) const { return _lhs < _rhs; } }
在此基礎(chǔ)上,當(dāng)關(guān)聯(lián)式容器中存儲(chǔ)的數(shù)據(jù)類型為自定義的結(jié)構(gòu)體變量或者類對象時(shí),通過對現(xiàn)有排序規(guī)則中所用的關(guān)系運(yùn)算符進(jìn)行重載,也能實(shí)現(xiàn)自定義排序規(guī)則的目的。
注意,當(dāng)關(guān)聯(lián)式容器中存儲(chǔ)的元素類型為結(jié)構(gòu)體指針變量或者類的指針對象時(shí),只能使用函數(shù)對象的方式自定義排序規(guī)則,此方法不再適用。
舉個(gè)例子:
#include <iostream> #include <set> // set #include <string> // string using namespace std; //自定義類 class myString { public: //定義構(gòu)造函數(shù),向 myset 容器中添加元素時(shí)會(huì)用到 myString(string tempStr) :str(tempStr) {}; //獲取 str 私有對象,由于會(huì)被私有對象調(diào)用,因此該成員方法也必須為 const 類型 string getStr() const; private: string str; }; string myString::getStr() const{ return this->str; } //重載 < 運(yùn)算符,參數(shù)必須都為 const 類型 bool operator <(const myString &stra, const myString & strb) { //以字符串的長度為標(biāo)準(zhǔn)比較大小 return stra.getStr().length() < strb.getStr().length(); } int main() { //創(chuàng)建空 set 容器,仍使用默認(rèn)的 less<T> 排序規(guī)則 std::set<myString>myset; //向 set 容器添加元素,這里會(huì)調(diào)用 myString 類的構(gòu)造函數(shù) myset.emplace("http://jb51.net.net/stl/"); myset.emplace("http://jb51.net.net/c/"); myset.emplace("http://jb51.net.net/python/"); // for (auto iter = myset.begin(); iter != myset.end(); ++iter) { myString mystr = *iter; cout << mystr.getStr() << endl; } return 0; }
程序執(zhí)行結(jié)果為:
http://jb51.net.net/c/
http://jb51.net.net/stl/
http://jb51.net.net/python/
在這個(gè)程序中,雖然 myset 容器表面仍采用默認(rèn)的 std::less<T> 排序規(guī)則,但由于我們對其所用的 < 運(yùn)算符進(jìn)行了重載,使得 myset 容器內(nèi)部實(shí)則是以字符串的長度為基準(zhǔn),對各個(gè) mystring 類對象進(jìn)行排序。
另外,上面程序以全局函數(shù)的形式實(shí)現(xiàn)對 < 運(yùn)算符的重載,還可以使用成員函數(shù)或者友元函數(shù)的形式實(shí)現(xiàn)。其中,當(dāng)以成員函數(shù)的方式重載 < 運(yùn)算符時(shí),該成員函數(shù)必須聲明為 const 類型,且參數(shù)也必須為 const 類型:
bool operator <(const myString & tempStr) const { //以字符串的長度為標(biāo)準(zhǔn)比較大小 return this->str.length() < tempStr.str.length(); }
至于參數(shù)的傳值方式是采用按引用傳遞還是按值傳遞,都可以(建議采用按引用傳遞,效率更高)。
同樣,如果以友元函數(shù)的方式重載 < 運(yùn)算符時(shí),要求參數(shù)必須使用 const 修飾:
//類中友元函數(shù)的定義 friend bool operator <(const myString &a, const myString &b); //類外部友元函數(shù)的具體實(shí)現(xiàn) bool operator <(const myString &stra, const myString &strb) { //以字符串的長度為標(biāo)準(zhǔn)比較大小 return stra.str.length() < strb.str.length(); }
當(dāng)然,本節(jié)所講自定義排序規(guī)則的方法并不僅僅適用于 set 容器,其它關(guān)聯(lián)式容器(map、multimap、multiset)也同樣適用,有興趣的讀者可自行編寫代碼驗(yàn)證。
到此這篇關(guān)于C++ STL關(guān)聯(lián)式容器自定義排序規(guī)則的2種方法的文章就介紹到這了,更多相關(guān)C++ STL關(guān)聯(lián)式容器自定義排序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++實(shí)現(xiàn)獲取硬盤序列號(hào)的示例代碼
獲取硬盤的序列號(hào)、型號(hào)和固件版本號(hào),此類功能通常用于做硬盤綁定或硬件驗(yàn)證操作,下面我們就來學(xué)習(xí)一下如何使用C/C++實(shí)現(xiàn)獲取硬盤序列號(hào)吧2023-11-11關(guān)于VS2019 C++項(xiàng)目同時(shí)出現(xiàn)LNK2005 和LNK1169 error 的解決辦法
這篇文章主要介紹了關(guān)于VS2019 C++項(xiàng)目同時(shí)出現(xiàn)LNK2005 和LNK1169 error 的解決辦法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04關(guān)于python調(diào)用c++動(dòng)態(tài)庫dll時(shí)的參數(shù)傳遞問題
這篇文章主要介紹了python調(diào)用c++動(dòng)態(tài)庫dll時(shí)的參數(shù)傳遞,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04c++讀取數(shù)據(jù)文件到數(shù)組的實(shí)例
今天小編就為大家分享一篇c++讀取數(shù)據(jù)文件到數(shù)組的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07