map 學習(上)——C++中 map 的使用

map 學習(上)——C++中 map 的使用

欠下數據結構的債,遲早是要還的…… 最近寫畢業論文過程中,需要用到哈希表的數據結構,此外空閒時間在刷 Leetcode 過程中,發現好多高效算法都是用 unordered_map 實現的,看來學習 map 相關內容是躲不了的了,開始學習 map 的相關內容。
本篇先學習 C++ 中 STL 標準庫中 map 的使用方法。

以下內容翻譯自:《map - C++ Reference》

一、原型

template < class Key,                                     // map::key_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;

二、說明

map 是一種容器,用來存儲若干元素,這些元素都是由關鍵值 (Key Value,以下稱爲 Key 值) 和映射值 (Mapped Value,以下依舊稱爲映射值) 配對組成的,具體說明如下:
在一個 map 中, Key 值通常用來排序或特指元素,映射值用來存儲與該 Key 值綁定的內容。 Key 值與映射值的數據類型可以不同,而且可以一起被放進成員類型 value_type 中,value_type 是一種配對類型,定義如下:

typedef pair<const Key, T> value_type;

在 map 內部的元素通常按照其 Key 值排序,且排序方式是根據某種明確、嚴格的弱排序標準進行的,這種排序標準是由 map 內部的比較對象(即 map::key_comp)指定的。
map 容器通過 Key 值訪問特定元素的速度,相較於 unordered_map 容器通常較慢,但 map 容器允許基於它們的順序對子集進行直接迭代。
map 中的映射值可以使用括號運算符 (operator[]) 通過其關聯的 Key 值直接訪問。
map 通常使用二叉搜索樹實現。

三、map 容器屬性

  • 關聯性:
    • 關聯容器中的元素的參考地址指的是其 Key 值,而不是他們在容器中的絕對地址;
  • 有序性:
    • 容器中的元素一直按照排序方式嚴格排序,所有插入元素都按照該順序排列;
  • 映射:
    • 每個元素中,一個 Key 值與一個映射值相關。Key 值是用來標識其主要內容是映射值的元素;
  • 唯一 Key 值:
    • 容器中不存在同時擁有相同 Key 值的兩個元素;
  • 分配感知 (Allocator-aware):
    • map 容器使用分配器對象動態處理其存儲需求。

四、模板參數

  • Key
    • Key 值的類型。在 map 中的每個元素都是由其 Key 值唯一指定的。
    • 別名爲成員類型 map::key_type
  • T
    • 映射值的類型。在 map 中的每個元素,都存儲了一些數據作爲其映射值。
    • 別名爲成員類型 map::mapped_type
  • Compare
    • 一個二元值,它將兩個元素的 Key 值作爲輸入參數,並返回一個布爾值。表達式 comp(a, b),其中 comp 是該類型的對象,a, b是 Key 值,如果按照函數定義的嚴格弱排序,參數 a 被認爲排在參數 b 之前,則返回 true。
    • map 對象使用該表達式確定元素在容器中的位置,並判斷兩個元素的 Key 值是否相等(通過自反比較:如果 (!comp(a,b) && !comp(b,a) ) 結果爲真,則 a, b 等價)。map 容器中沒有兩個元素擁有相同的 Key 值。
    • Compare 可以使一個函數指針,或者函數對象(詳細請參閱示例構造函數)。默認值小於<T>,返回應用小於運算符 (a < b) 相同的值;
    • 別名爲成員類型 map::key_compare
  • Alloc
    • 用於定義存儲分配模型的分配器對象的類型。默認情況下使用分配器類模板,它定義了最簡單的模型分配模型,而且與值無關。
    • 別名爲成員類型 map::allocator_type

五、常用函數

  • 構造函數
    • 在後續的程序示例中展示了五種不同的構造函數;
  • clear
    • 清除 map 中所有元素;
  • erase
    • 刪除 map 中指定位置的元素;
  • insert
    • 在 map 指定位置添加 pair 類型的元素;
  • find
    • 獲取 map 中元素的迭代器;
  • begin, end
    • map 的正向迭代器的起始位置與終點位置;
  • rbegin, rend
    • map 的反向迭代器的起始位置與終點位置;

六、程序示例

以下源碼摘自《C++STL之map學習》,筆者對其進行註釋。

#include <iostream>
#include <map>

using namespace std;

// 比較函數(用於後面的函數指針定義)
bool fncomp(char lhs, char rhs){
    return lhs < rhs;
}

// 定義一個 Compare 對象,且內部對運算符 () 進行重載
struct classcomp{
    bool operator() (const char& lhs, const char& rhs){
        return lhs < rhs;
    }
};

int main(int argc, char* argv[])
{
    //=========================
    //  map 的多種構造函數
    //=========================

    // 1. 直接定義
    map<char,int> mymap;
    mymap['a'] = 10;
    mymap['b'] = 60;
    mymap['c'] = 30;
    mymap['d'] = 90;
    mymap['e'] = 50;

    // 2. 複製
    map<char, int> second(mymap);

    // 3. 通過迭代器
    map<char, int> third(mymap.begin(),mymap.end());

    // 4. 重新定義 Compare 對象,該對象內部對運算符 () 進行重載
    map<char, int, classcomp> fourth;

    // 5. 通過函數指針
    bool(*fn_pt)(char, char) = fncomp;
    map<char, int, bool(*)(char, char)> fifth(fn_pt);

    //=========================
    //  以最初定義的mymap 爲例,講解 map 的使用
    //=========================
    map<char,int>::key_compare key_comp;
    map<char,int>::iterator it;
    it = mymap.begin();


    //=========================
    //  1. 輸出所有 Pair 元素
    //=========================
    // 迭代器遍歷 map
    for (it; it != mymap.end(); it++)
    {
        // map的迭代器,可以用 first 訪問std::pair的第一個成員(Type1),second 訪問第二個成員 (Type2)
        cout<<it->first<<":"<<it->second<<endl;
    }
    cout<<"================================="<<endl;

    //=========================
    //  2. 修改映射值
    //=========================
    second.clear();
    second['a']=1002;
    second['b']=10023;
    while (!second.empty())
    {
        cout << second.begin()->first << " => ";
        cout << second.begin()->second << endl;
        second.erase(second.begin());
    }
    cout<<"================================="<<endl;

    //=========================
    //  3. 插入
    //=========================
    mymap.insert(pair<char,int>('f',100) );
    mymap.insert(pair<char,int>('g',200) );
    cout<<"f => " <<mymap.find('f')->second<<endl;
    cout<<"g => " <<mymap.find('g')->second<<endl;

    cout<<"================================="<<endl;

    //=========================
    //  4. Compare 參數的使用
    //=========================
    key_comp = mymap.key_comp();
    cout << "mymap contains:\n";

    // 迭代器反向遍歷的起始位置
    char highest = mymap.rbegin()->first;     // key value of last element
    it = mymap.begin();
    do {
        cout << (*it).first << " => " << (*it).second << endl;
    } while ( key_comp((*it++).first, highest) );

    cout << endl;
    return 0;
}

運行結果如下:
這裏寫圖片描述

發佈了60 篇原創文章 · 獲贊 259 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章