C++ map容器 學習筆記

此篇爲轉載內容,對原作者表示感謝!


map映照容器的元素數據是一個由鍵值和一個映照數據組成的,鍵值與映照數據之間具有一一映照的關係。
map映照容器的數據結構也是採用紅黑樹來實現的,插入元素的鍵值不允許重複,比較函數只對元素的鍵值進行比較,元素的各項數據可通過鍵值檢索出來,由於map與set採用的都是紅黑樹的數據結構,所以,用法基本相似,下圖是map映照容器元素的數據構成示意圖;
 
鍵值 映照數據    
Name Score    
Jack 98.5    
Bomi 96.0    
Kate 97.5   

使用map容器需要頭文件包含語句#include <map>,map文件也包含了對multimap多重映照容器的定義;

map創建,元素插入和遍歷訪問


創建map對象,鍵值與映照數據的類型由自己定義,在沒有指定比較函數時,元素的插入位置是按鍵值由小到大插入到黑白樹中去的,這點和set一樣;
下例程序詳細說明了如何操作map容器:


運行結果爲:
Bomi : 96.0
Jack : 98.5
Kate : 97.5

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

int main(int argc, char *argv[])
{
    //定義map對象,當前沒有任何元素
    map <string, float> mp;
    mp["Jack"] = 98.5;
    mp["Bomi"] = 96.0;
    mp["Kate"] = 97.5;
    //前向遍歷元素;
    map <string, float> :: iterator it;  //定義前向迭代器;
    for(it=mp.begin(); it != mp.end(); it++) {
        //輸出鍵值與映照數據;
        cout << (*it).first << " : " << (*it).second << endl;
    }
    return 0;
}


map元素的刪除

與set容器一樣,map映照容器的erase()刪除元素函數,可以死刪除某個迭代器位置上的元素,等於某個鍵值的元素,一個迭代器區間上的所有元素,當然也可使用clear()的方法清空map映照容器;
下例程序演示了刪除map容器中鍵值爲28的元素:


運行結果爲:
7 : t
10 : x
25 : m
30 : a

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

int main(int argc, char *argv[])
{
    //定義map對象,當前沒有任何元素
    map <int, char> mp;
    //插入元素,按鍵值的由小到大放入黑白樹中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    //刪除鍵值爲28的元素;
    mp.erase(28);
    //前向遍歷元素;
    map <int, char> :: iterator it;  //定義前向迭代器;
    for(it=mp.begin(); it != mp.end(); it++) {
        //輸出鍵值與映照數據;
        cout << (*it).first << ":" << (*it).second << endl;
    }
    return 0;
}


map元素的反向遍歷

可以使用反向迭代器reverse_iterator反向遍歷map映照容器中的數據,他需要rbegin()方法和rend()方法指出反向遍歷的起始位置和終止位置;
下例程序詳細說明了map容器反向遍歷的方法:

運行結果爲:
30:a
28:k
25:m
10:x
7:t

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

int main(int argc, char *argv[])
{
    //定義map對象,當前沒有任何元素
    map <int, char> mp;
    //插入元素,按鍵值的由小到大放入黑白樹中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    //反向遍歷元素;
    map <int, char> :: reverse_iterator rit;  //定義反向迭代器;
    for(rit=mp.rbegin(); rit != mp.rend(); rit++) {
        //輸出鍵值與映照數據;
        cout << (*rit).first << ":" << (*rit).second << endl;
    }
    return 0;
}


map元素的搜索

使用find()方法來搜索某個鍵值,如果搜索到了,則返回該鍵值鎖在的迭代器位置,否則,返回end()迭代器的位置,由於map採用黑白樹數據結構來實現,所以搜索速度是極快的;
下例程序搜索鍵值爲28的元素:

運行結果爲:
28 : 'k'

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

int main(int argc, char *argv[])
{
    //定義map對象,當前沒有任何元素
    map <int, char> mp;
    //插入元素,按鍵值的由小到大放入黑白樹中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    //前向遍歷元素;
    map <int, char> :: iterator it;  //定義前向迭代器;
    //查找鍵值爲28的元素;
    it = mp.find(28);
    if(it != mp.end()) {   //找到
        cout << (*it).first << " : " << (*it).second << endl;
    }else {   //沒找到
        cout << "Not find it!" << endl;
    }
    return 0;
}

map 自定義比較函數

將元素插入到map中去的時候,map會根據設定的比較函數將該元素放到該放的節點上去,在定義map的時候,如果沒有指定比較函數,那麼就採用默認的比較函數,即按鍵值由小到大的順序插入元素,在很多情況下,需要自己編寫比較函數。
編寫比較函數與set比較函數是一致的,因爲它們的內部數據都是紅黑樹,編寫方法有兩種;
1>. 如果元素不是結構體,那麼,可以編寫比較函數,下例程序編寫的比較規則是要求按鍵值有大到小的順序將元素插入到map中:

運行結果爲:
30:a
28:k
25:m
10:x
7:t

The Code Follows:

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

struct mycmp
{
    bool operator () (const int &a, const int &b)
    {
        return a > b;
    }
};

int main(int argc, char *argv[])
{
    //定義map對象,當前沒有任何元素
    map <int, char, mycmp> mp;
    //插入元素,按鍵值的由小到大放入黑白樹中;
    mp[25] = 'm';
    mp[10] = 'x';
    mp[28] = 'k';
    mp[30] = 'a';
    mp[7] = 't';
    map <int, char, mycmp> :: iterator it;  //定義前向迭代器中序遍歷map;
    for(it=mp.begin(); it != mp.end(); it++) {
        //輸出鍵值與映照數據;
        cout << (*it).first << ":" << (*it).second << endl;
    }
    return 0;
}


2>. 如果元素是結構體,那麼可以直接把比較函數寫在結構體內,下例程序詳細說明了操作方法:

運行結果:
10 : Bomi 80
30 : Peti 66.5
25 : Jack 60

The Code Follows:

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

struct Info
{
    string name;
    float score;
    //重載“<”操作符,自定義排序規則;
    bool operator < (const Info &a) const
    {
        //按score從大到小排列,如果要從小到大排列,使用“>”即可;
        return a.score < score;
    }
};

int main(int argc, char *argv[])
{
    //定義map對象,當前沒有任何元素;
    map <Info, int> mp;
    Info info;   //定義Info結構體變量;
    //插入元素,按鍵值的由小到大放入黑白樹中;
    info.name = "Jack";
    info.score = 60;
    mp[info] = 25;
    info.name = "Bomi";
    info.score = 80;
    mp[info] = 10;
    info.name = "Peti";
    info.score = 66.5;
    mp[info] = 30;
    //使用前向迭代器中序遍歷map;
    map <Info, int>:: iterator it;
    for(it=mp.begin(); it != mp.end(); it++) {
        cout << (*it).second << " : ";
        cout << ((*it).first).name << " " << ((*it).first).score << endl;
    }
    return 0;
}



我的總結:

map就是一個數組,只不過這個數組的下標可以是任意類型,下標的大小規則也可以自己定義,從前向後遍歷和從後向前遍歷需要定義不同的迭代器,可以實現O(logn)時間複雜度內查找某個下標的數據。

還有,(*it).first和(*it).second也可以寫成it->first和it->second。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章