映射(map)、複映射(multimap):
(1) 在map以及multimap中,一個節點所存取的資料有兩種,一為索引(key),一為資料值(value)。
(2) 在map中,一個索引只能對應一個資料值;而在multimap中,一個索引可以對應多個資料值。此二容器之中各節點的排列順序,是以索引的大小來做排列。預設是依索引的ASCII碼由小排到大。
(3) 使用者不能隨意修改某資料的索引,但可以修改某索引上的資料值。
(4) 一個映射或者複映射中,不容許兩個重複相同的索引。
(5) 資料值的資料型態,可為一般資料型態(int、bool…等)或是類別物件。
(6) 無論使用映射還是複映射,均需在標頭檔寫下#include <map>
1. 建構:
映射種類<索引資料型態 , 資料的資料型態> 名稱;
映射種類<索引資料型態 , 資料的資料型態 , 雙元判斷式> 名稱;
註一:映射種類可為map或multimap。
註二:以上的第一種建構方法,其實是默認less<索引資料型態>為雙元判斷式。
2. 成對結構資料型態:成對結構(pair structure)是C++內建的樣板結構,在建構映射和複映射時需要用到。成對結構有兩個成員:first和second,這兩個成員可以為不同的資料型態。建立一個成對結構有以下2種方法:
(1) pair<成員first的資料型態 , 成員second的資料型態> 成對結構名稱(成員first的值 , 成員second的值);
舉例:
pair<string , int> tt1("國文",98); //建構一個成對結構tt1
pair<string , int> tt2("英文",60); //建構一個成對結構tt2
cout<<tt1.first<<"考了"<<tt1.second<<"分。"<<endl; //顯示:國文考了98分。
cout<<tt2.first<<"考了"<<tt2.second<<"分。"<<endl; //顯示:英文考了60分。
(2)利用C++內建樣板函式make_pair():
pair<成員first的資料型態 , 成員second的資料型態> 成對結構名稱;
成對結構名稱 = make_pair(成員first的值 , 成員second的值);
舉例:
pair<string , int> tt1;
tt1=make_pair("國文",98);
pair<string , int> tt2;
tt2=make_pair("英文",60);
cout<<tt1.first<<"考了"<<tt1.second<<"分。"<<endl; //顯示:國文考了98分。
cout<<tt2.first<<"考了"<<tt2.second<<"分。"<<endl; //顯示:英文考了60分。
註:要將資料加入映射或者是複映射,必須先將資料轉換成成對結構。其中first對應索引,second對應資料值。
3. 將資料加入映射或複映射(需要使用上一篇所提到的「成對結構」):
(1)若要將資料加入映射,可使用:
(a)映射名稱.insert(成對結構名稱);
其中成對結構的成員first對應索引,成對結構的成員second對應資料。由於在映射中,一個索引只能對應一個資料,故若新加入的成對結構之first的值與映射中的某個索引值相同,則這個新加入的成對結構會被剔除掉,表示加入失敗了。
(b) 映射名稱.insert(迭代器 , 成對結構名稱);
由迭代器位址開始尋找適當的插入位址,以將成對結構加入映射。
若加入成功,insert函式回傳此成對結構在映射中的位址相應的迭代器。
(c) 映射名稱.insert(迭代器1 , 迭代器2);
將迭代器1到迭代器2之間(包含迭代器1、不包含迭代器2),的成對結構資料加入此映射,若新加入的成對結構之first的值與映射中的某個索引值相同,則這個新加入的成對結構會被剔除掉,即加入失敗的意思。
(2)若要將資料加入複映射,可使用:
(a)複映射名稱.insert(成對結構名稱);
其中成對結構的成員first對應索引,成對結構的成員second對應資料。
此函式會回傳一個迭代器,和新加入資料的位址對應。
(b) 複映射名稱.insert(迭代器 , 成對結構名稱);
由迭代器位址開始尋找適當的插入位址,以將成對結構加入複映射。
並回傳此成對結構在複映射中的位址相應的迭代器。
(c) 複映射名稱.insert(迭代器1 , 迭代器2);
將迭代器1到迭代器2之間(包含迭代器1、不包含迭代器2),的成對結構資料加入複映射。
此函式無回傳值。
(3) 範例:
class person
{
public:
string name;
int age;
person(string name_,int age_)
{name=name_;age=age_;}
};
void show(person m){
cout<<"我是"<<m.name<<",今年"<<m.age<<"歲。";}
int main() { //主程式在此
person m1("維維",18);
person m2("小藍",19);
person m3("雅芯",24);
person m4("小杜",27);
person m5("木村靜香",17);
map<int,person> a;
multimap<int,person> ma;
map<int,person> b;
multimap<int,person> mb;
map<int,person>::iterator i;
map<int,person>::iterator j;
a.insert(make_pair(85,m1));
a.insert(make_pair(90,m2));
a.insert(make_pair(77,m3));
a.insert(make_pair(82,m4));
a.insert(make_pair(77,m5));
ma.insert(make_pair(85,m1));
ma.insert(make_pair(90,m2));
ma.insert(make_pair(77,m3));
ma.insert(make_pair(82,m4));
ma.insert(make_pair(77,m5));
for(i=a.begin();i!=a.end();i++)
{
show(i->second);
cout<<"此次考試考了"<<i->first<<"分。"<<endl;
}
cout<<endl;
/* 顯示為(注意,最後一個加入的m5,是加入失敗的。):
我是雅芯,今年24歲。此次考試考了77分。
我是小杜,今年27歲。此次考試考了82分。
我是維維,今年18歲。此次考試考了85分。
我是小藍,今年19歲。此次考試考了90分。 */
for(i=ma.begin();i!=ma.end();i++)
{
show(i->second);
cout<<"此次考試考了"<<i->first<<"分。"<<endl;
}
cout<<endl;
/* 顯示為:
我是雅芯,今年24歲。此次考試考了77分。
我是木村靜香,今年17歲。此次考試考了77分。
我是小杜,今年27歲。此次考試考了82分。
我是維維,今年18歲。此次考試考了85分。
我是小藍,今年19歲。此次考試考了90分。*/
i=ma.begin();
j=ma.end();
j--; j--;
b.insert(i,j);
mb.insert(i,j);
for(i=b.begin();i!=b.end();i++)
{
show(i->second);
cout<<"此次考試考了"<<i->first<<"分。"<<endl;
}
cout<<endl;
/* 顯示為:
我是雅芯,今年24歲。此次考試考了77分。
我是小杜,今年27歲。此次考試考了82分。 */
for(i=mb.begin();i!=mb.end();i++)
{
show(i->second);
cout<<"此次考試考了"<<i->first<<"分。"<<endl;
}
cout<<endl;
/* 顯示為:
我是雅芯,今年24歲。此次考試考了77分。
我是木村靜香,今年17歲。此次考試考了77分。
我是小杜,今年27歲。此次考試考了82分。*/
}
// 註:以上均以分數為索引,可見資料是依分數由小排到大。
4. 下標運算子[]
映射可以和矩陣一樣,使用下標運算子[]來直接藉由索引存取資料值。如:
map<int , string> b;
b[85]="唐某";
b[116]="李某";
cout<<b[85]<<endl; //顯示:唐某
註:此種方法只有映射能用,對複映射而言,此法是沒有效果的。