難道插入map還有什么講究嗎?我們且看map在STL中的定義方法:
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
第一個參數Key是關鍵字類型
第二個參數T是值類型
第三個參數Compare是比較函數(仿函數)
第四個參數是內存配置對象
map內部存儲機制實際是以紅黑樹為基礎,紅黑樹在插入節點時,必須依照大小比對之后在一個合適的位置上執行插入動作。所以作為關鍵字,起碼必須有“<”這個比較操作符。我們知道,int,float,enum,size_t等等簡單關鍵字,都有內置的比較函數,與map搭配無論是插入還是查找,都沒什么問題。但是作為復雜數據類型,如果沒有明確定義“<”比較操作符,就不能與map直接搭配使用,除非我們自己定義第三個參數。
在選擇map的關鍵字時,注意以下兩點,同時這兩點也是改錯的方法:
a) 關鍵字明確定義“<”比較操作符
b) 沒有“<”比較操作符,自定義仿函數替代第三個參數Compare,該仿函數實現“()”操作符,提供比較功能。插入時各節點順序以該仿函數為綱。
以std::pair為關鍵字摻入map
下面我們先寫一個有錯誤的函數,在分析錯誤原因之后,逐步進行修正。
#include <map>
int main()
{
std::map<std::pair<int, int>, int> res;
res.insert(std::make_pair(12,33), 33);
}
這個程序一定失敗,如果非要如此使用,上述a方法顯然不適合,std::pair是已定義好的結構體不可修改。只能使用b方法了,定義一個比較類改造如下:
#include <map>
struct comp
{
typedef std::pair<int, int> value_type;
bool operator () (const value_type & ls, const value_type &rs)
{
return ls.first < rs.first || (ls.first == rs.first && ls.second < rs.second);
}
};
int main()
{
std::map<std::pair<int, int>, int, comp> res;
res.insert(std::make_pair(std::make_pair(12,33), 33));
res.insert(std::make_pair(std::make_pair(121,331), 331));
res.insert(std::make_pair(std::make_pair(122,332), 332));
std::map<std::pair<int, int>, int, comp>::iterator it = res.find(std::make_pair(121,331));
if (it == res.end())
printf("NULL"n");
else
printf("%d %d %d "n", it->first.first, it->first.second, it->second);
return 0;
}
以結構體或類為關鍵字插入map
#include <map>
struct st
{
int a, b;
st():a(0), b(0){}
st(int x, int y):a(x), b(y){}
};
int main()
{
std::map<struct st, int> res;
res.insert(std::make_pair(st(1,2), 12));
res.insert(std::make_pair(st(30,4), 34));
res.insert(std::make_pair(st(5,6), 56));
std::map<struct st, int>::iterator it = res.find(st(30,4));
if (it == res.end())
printf("NULL"n");
else
printf("first:%d second:%d %d"n", it->first.a, it->first.b, it->second);
return 0;
}
編譯這個程序也是錯誤的,錯誤意思大概也是沒有定義“<”比較函數。因為struct st是我們自己定義的結構體,所以修改這個程序可以使用上面a、b兩種方法。我們先談第一種,第一次修改時我也搞錯了,我是這樣定義比較函數的。
struct st
{
int a, b;
st():a(0), b(0){}
st(int x, int y):a(x), b(y){}
bool operator < (const struct st &rs) {return (this->a < rs.a || (this->a == rs.a && this->b < rs.b));}
};
按照這個改動再次編譯程序還是錯誤,有個如下這樣的提示:
/usr/include/c++/3.2.3/bits/stl_function.h:197: passing `const st' as `this' argument of `bool st::operator<(const st&)' discards qualifiers
為什么會出現這個問題呢?我們深入STL的源代碼看下。既然說是/usr/include/c++/3.2.3/bits/stl_function.h的197行出了問題,且看這行是什么。
193 /// One of the @link s20_3_3_comparisons comparison functors@endlink.
194 template <class _Tp>
195 struct less : public binary_function<_Tp,_Tp,bool>
196 {
197 bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }
198 };
struct st中的“<”在編譯后真正是什么樣子呢?大概是bool operator < (struct st &ls, const struct st &rs)。在less調用這個比較符時,它都是以const方式傳入,不可能再以非const方式調用,故出錯。修正如下:
struct st
{
int a, b;
st():a(0), b(0){}
st(int x, int y):a(x), b(y){}
friend bool operator < (const struct st &ls, const struct st &rs);
};
inline bool operator < (const struct st &ls, const struct st &rs)
{return (ls.a < rs.a || (ls.a == rs.a && ls.b < rs.b));}
以友聯函數代替函數內部定義的比較操作符,STL內部也多是以這種方式定義的。如果我非要以內部定義的方式呢?可以使用b方法,我們自定義一個比較仿函數,替代默認的less。
插入函數返回值
在map容器中插入數據有很多函數可用,這里只討論最普通的insert操作,在STL中它是這樣定義的。
pair<iterator, bool> insert(const value_type& x);
map容器不允許鍵值重復,在執行插入操作后,可以憑借該返回值獲取操作結果。返回值是一個迭代器和布爾值的鍵值對,迭代器指向map中具有該值的元素,布爾值表示是否插入成功。如果布爾值為true,表示插入成功,則迭代器為新插入值在map中的位置;布爾值為false,表示插入失?。ㄒ呀洿嬖谠撝担?,迭代器為原有值在map中的位置。