STL與泛型編程<六>:map和multimap


Map和Multimap將key/value pair當作元素,進行管理。它們可根據key的排序准則自動將元素進行排序。其聲明如下

namespace std
{
template<class key, class T,
class Compare = less<key>,
class Allocator = allocator<pair<const Key, T> > >
class map;

template<class key, class T,
class Compare = less<key>,
class Allocator = allocator<pair<const Key, T> > >
class multimap;
}
  1. key/value必須具備assignable(可賦值的)和copyable(可復制的)性質
  2. 對排序准則來說,key必須是comparable(可比較的)

maps和multimaps的能力

內部結構如下圖
這里寫圖片描述
和set一樣,map具有很好的排序功能,當然你不能改變其key,因為破壞了正確次序。要修改元素的key,必須先移除擁有該key的元素,然后插入新的key/value.

maps和multimaps的操作函數

  • 生成 賦值 銷毀
    這里寫圖片描述
  • 非變動性操作
    這里寫圖片描述
    元素的比較只能用於相同型別的容器,也就是容器的key/value/排序准則都必須一樣。
  • 特殊的搜尋動作
    這里寫圖片描述
    你不能以find()搜尋擁有某特定value的元素,必須使用通用算法find_if(),或寫一個顯示循環。
  • 賦值
    這里寫圖片描述
  • 迭代器函數和元素存取
    這里寫圖片描述
    由於key的類型是const,所以不能直接改變。若要改變key,只能以一個”value相同”的新元素替代換掉舊元素,見下面的函數
template <typename T>
inline bool replace_key(T& c, const T::key_type& old_key, const T::key_value& new_key)
{
typename T::iterator pos;
pos = c.find(old_key);
if (pos != c.end())
{
c.insert(typename T::value_type(new_key,pos->second));
c.erase(pos);
return true;
}
else
return false;
}

注意由於maps可以用[]來存取元素,因此還可以這樣來替換key

col["new_key"] = col["new_key"];
col.erase("old_keys");
  • 元素的安插和移除
    和sets和multisets一樣,只是返回值不一樣,是key/value pair。
    安插一個key/value時,一定要記住,在map和multimap內部,key被視為常數,元素的實質類型為pair
map<string,float> col;
col.insert(map<string,float>::value_type("otto",22.3));
  1. 運用pair<>
map<string,float> col;
//use implicit conversion
col.insert(pair<string,float>("otto",22.3));
//use no implicit conversion
col.insert(pair<const string,float>("otto",22.3));
  1. 運用make_pair()
map<string,float> col;
col.insert(make_pair("otto",22.3));

最方便的就是make_pair了,下面是個簡單的例子,檢查插入是否成功


map<string,float> col;
if ( col.insert(make_pair("shi",12.3)).second ) //插入成功
{

}
else//插入失敗

如果想要移除擁有某個value元素,可以運用erase()可辦到,其返回移除元素的個數,對於map來說不是0就是1

col.erase(key);

如果multimap內含有重復元素,你不能使用erase()來刪除這些重復元素中的第一個(因為C++根本不知道刪除的是哪一個),你可以這么做

multimap<string,int> col;
...
multimap<string,int>::iterator pos;
pos = col.find(key);
if (pos != key)
{
col.erase(key);
}

以下重要移除元素時,當你移除迭代器所指對象時,有一個很大的危險

map<string,int> col;
...
multimap<string,int>::iterator pos;
for (pos=col.begin(); pos != col.end(); ++pos)
{
if (pos->second == value)
col.erase(pos);
}

如果刪除了pos,光是一個++pos就會產生未定義行為。
下面是移除“迭代器所指元素的正確做法”

map<string,int> col;
...
multimap<string,int>::iterator pos;
for (pos=col.begin(); pos != col.end();)
{
if (pos->second == value)
col.erase(pos++);
else
++pos;
}

至於為什么,只要懂得前置++和后置++的一看就明白了。

  • 將map置為關聯式數組
    通常關聯是容器並不提供元素的直接存取,你必須依靠迭代器,不過map是個例外
m[key];//返回一個reference,指向鍵值為key的元素,如果該元素不存在,就安插該元素

注意你不可能用上一個錯誤的索引,而容器中尚未存在對應元素,那么就會自動安插該元素,新元素的value會由default構造函數構造
1. 優點:很容易就可以安插元素
2. 缺點:很容易安插錯誤的元素

  • map應用實例
#include <iostream>
#include <map>
#include <iterator>

using namespace std;

int main(void)
{
map<string,float> stocks;
stocks["BASF"] = 369.50;
stocks["VW"] = 413.50;
stocks["Daimler"] = 819.00;
stocks["BMW"] = 834.00;
stocks["Simens"] = 842.20;

map<string,float>::iterator pos;
for (pos=stocks.begin(); pos!=stocks.end(); ++pos)
{
cout << "stocks: " << pos->first << "\t"
<< "prices: " << pos->second << endl;
}
cout << endl;

for (pos=stocks.begin(); pos!=stocks.end(); ++pos)
{
pos->second *= 2;
}

for (pos=stocks.begin(); pos!=stocks.end(); ++pos)
{
cout << "stocks: " << pos->first << "\t"
<< "prices: " << pos->second << endl;
}

stocks["Volk"] = stocks["VW"];
stocks.erase("VW");

return 0;
}
  • multimap當作字典
#include <iostream>
#include <map>
#include <iomanip>

using namespace std;

int main(void)
{
multimap<string,string> dict;

dict.insert(make_pair("day","Tag"));
dict.insert(make_pair("strange","Atuo"));
dict.insert(make_pair("smart","elegant"));
dict.insert(make_pair("trait","Merkmal"));
dict.insert(make_pair("strange","seltsam"));
dict.insert(make_pair("smart","klug"));
dict.insert(make_pair("clever","raffiniert"));

multimap<string,string>::iterator pos;
cout.setf (ios::left, ios::adjustfield);
cout << ' ' << setw(10) << "english "
<< "german " << endl;
cout << setfill('-') << setw(20) << " "
<< setfill(' ') << endl;

for (pos=dict.begin(); pos!=dict.end(); ++pos)
{
cout << ' ' << setw(10) << pos->first.c_str()
<< pos->second << endl;
}
cout << endl;

string word("smart");
cout << word << ": " << endl;
for (pos=dict.lower_bound(word); pos!=dict.upper_bound(word); ++pos)
{
cout << " " << pos->second << endl;
}

word = ("raffinert");
cout << word << ": " << endl;
for (pos=dict.begin(); pos!=dict.end(); ++pos)
{
if (pos->second == word)
cout << " " << pos->first << endl;
}
return 0;
}
  • 搜尋某個特定實值(values)的元素
    解法1:自己寫仿函數
#include <iostream>
#include <algorithm>
#include <map>
#include <functional>

using namespace std;

template<typename K, typename V>
class value_equals
{
private:
V _val;
public:
value_equals(const V& val) : _val(val) {}
bool operator() (pair<const K,V> elem)
{
return elem.second == _val;
}
};

int main(void)
{
map<float,float> col;
map<float,float>::iterator pos;
col[1] = 7;
col[2] = 4;
col[3] = 2;
col[4] = 3;
col[5] = 6;
col[6] = 1;
col[7] = 3;

pos = col.find(3);
if (pos != col.end())
cout << pos->first << ":" << pos->second << endl;
pos = find_if(col.begin(),col.end(),value_equals<float,float>(3));
if (pos != col.end())
cout << pos->first << ":" << pos->second << endl;
return 0;
}
/*
上面是寫了個仿函數,
*/

解法2:使用全局函數

#include <iostream>
#include <algorithm>
#include <map>
#include <functional>
using namespace std;

template<typename K, typename V>
bool my_equal(pair<const K,V> elem, V val)
{
return elem.second == val;
}

int main(void)
{
map<float,float> col;
map<float,float>::iterator pos;
col[1] = 7;
col[2] = 4;
col[3] = 2;
col[4] = 3;
col[5] = 6;
col[6] = 1;
col[7] = 3;

pos = col.find(3);
if (pos != col.end())
cout << pos->first << ":" << pos->second << endl;
pos = find_if(col.begin(),col.end(),bind2nd(ptr_fun(my_equal<float,float>),3));
if (pos != col.end())
cout << pos->first << ":" << pos->second << endl;
return 0;
}
/*
寫個全局函數,然后使用ptr_fun()接口使之能夠使用仿函數適配器
*/

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com