STL 映射类

map、multimap

map、multimap 是键-值对容器,根据键进行查找。

同样地,由于其内部结构类似二叉树,因此在插入元素时要进行排序;不能像 vector 使用其他元素替换给定位置的元素。

头文件:#include <map>

实例化

/*
实例化语法:
	map <keyType, valueType, Predicate=std::less <keyType>> mapObj; 
	multimap <keyType, valueType, Predicate=std::less <keyType>> mmapObj; 
	第三个模板参数可选:默认是std::less<>用作排序标准
*/

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

template <typename T>
struct reverseSort
{
    bool operator()(const T& key1, const T& key2)
    {
        return key1 > key2;
    }
};

int main()
{
    // 初始化1:int -> string
    map <int, string> mapIntToString1;
    multimap <int, string> multimapIntToString1;

    // 2. 以另一个 map/multimap 进行初始化
    map <int, string> mapIntToString2(mapIntToString1);
    multimap <int, string> multimapIntToString2(multimapIntToString2);

    // 3. 以另一个 map/multimap 的一部分进行初始化
    map <int, string> mapIntToString3(mapIntToString1.cbegin(),
                                        mapIntToString1.cend());
    multimap <int, string> multimapIntToString3(multimapIntToString1.cbegin(),
                                                multimapIntToString1.cend());
    
    // 4. 带谓词的初始化
    map <int, string, reverseSort<int>> mapIntToString4
        (mapIntToString1.cbegin(), mapIntToString1.cend());
    // 用map实例化multimap
    multimap <int, string, reverseSort<int>> multimapIntToString4
        (mapIntToString1.cbegin(), mapIntToString1.cend());
    system("pause");
    return 0;
}

插入

/*
用成员函数 insert:
    1. make_pair(key, value)
    2. std::pair(key, value)
    3. 类似数组的语法:mapIntToStr [1000000] = "One Million"; 
*/
#include <iostream>
#include <string>
#include <map>
using namespace std;

typedef map <int, string> MAP_INT_STRING;
typedef multimap <int, string> MMAP_INT_STRING;

template <typename T>
void DisplayElement (const T& input)
{
    for (auto iElement = input.cbegin(); iElement != input.cend(); ++iElement)
    {
        cout << iElement->first << " -> " << iElement->second << endl;
    }
    cout << endl;
}

int main()
{
    MAP_INT_STRING mapIntToString;
    // value_type:stl容器盛装的数据的数据类型,这里就是<int, string>
    mapIntToString.insert(MAP_INT_STRING::value_type(3, "Three"));
    
    // make_pair (key, value)
    mapIntToString.insert(make_pair(-1, "Minus one"));

    // pair
    mapIntToString.insert(pair <int, string> (1000, "One thousand"));
     
    // 数组语法添加元素
    mapIntToString[1000000] = "One million";

    cout << "The map contains " << mapIntToString.size();
    cout << " key-value pairs. They are: " << endl;
    DisplayElement(mapIntToString);

    // 以map实例化一个multimap
    MMAP_INT_STRING mmapIntToString (mapIntToString.cbegin(),
                                                     mapIntToString.cend());
    mmapIntToString.insert(make_pair(1000, "Thousand"));
    cout << endl << "The multimap contains" << mmapIntToString.size();
    cout << "The elements in the multimap are: " << endl;
    DisplayElement(mmapIntToString);

    cout << "The number of pairs in the mutimap with 1000 as their key: "
        << mmapIntToString.count(1000) << endl;
    system("pause");
    return 0;
}

查找

multimap::find() 总返回一个迭代器,如:

auto pairFound = mmapIntToStr.find(key); // C++11
mutimap <int, string>::const_iterator iPairFound = mapIntToString.find(key);

再次提醒:

使用该迭代器之前首先要检查,确保 find() 返回成功再使用它访问找到的值:

if (pairFound != mapIntToStr.end()) 
{ 
	cout << "Key " << pairFound->first << " points to Value: "; 
	cout << pairFound->second << endl; 
} 
else 
	cout << "Sorry, pair with key " << key << " not in map" << endl; 

关于成员 multimap::find() 的用法:

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

template <typename T>
void DisplayContents (const T& input)
{
    for (auto iElement = input.cbegin()
        ; iElement != input.cend()
        ; ++iElement)
    {
        cout << iElement->first << " points to "
            << iElement->second << endl;
    }
    cout << endl;
    
}

int main()
{
    map <int, string> mapIntToString;
    mapIntToString.insert(make_pair(3, "Three"));
    mapIntToString.insert(make_pair(45, "Fifty five"));
    mapIntToString.insert(make_pair(-1, "Minus one"));
    mapIntToString.insert(make_pair(1000, "One Thousand"));
    cout << "The map contains " << mapIntToString.size();
    cout << " key-value pairs. They are:" << endl;
    DisplayContents(mapIntToString);

    cout << "Enter the key you wish to find: ";
    int key = 0;
    cin >> key;

    auto iPairFound = mapIntToString.find(key);
    if (iPairFound != mapIntToString.cend())
    {
        cout << "Key " << iPairFound->first << " points to Value: ";
        cout << iPairFound->second << endl;
    }
    else
    {
        cout << "The pair with key " << key << " not in map" << endl;
    }
    system("pause");
    return 0;
}

查找

multimap::count( ) 确定有多少个值与指定的键对应,再对迭代器递增来访问这些相邻的值:

auto pairFound = mmapIntToStr.find(key); 
// Check if find() succeeded 
if(pairFound != mmapIntToStr.end()) 
{ 
    // Find the number of pairs that have the same supplied key 
    size_t numPairsInMap = mmapIntToStr.count(1000); 
    for(size_t counter = 0; 
    counter < numPairsInMap; // stay within bounds 
    ++ counter ) 
    { 
        cout << "Key: " << pairFound->first; // key 
        cout << ", Value [" << counter << "] = "; 
        cout << pairFound->second << endl; // value 
        ++ pairFound; // ******递增迭代*******
    } 
} 
else 
     cout << "Element not found in the multimap"; 

删除

/*
    1. 将键作为参数,这将删除包含指定键的所有键-值对:
        mapObject.erase (key);
    
    2. 接受迭代器作为参数,并删除迭代器指向的元素:
        mapObject.erase(element); 

    3. 使用迭代器指定边界,从而将指定范围内的所有元素都从 map 或 multimap 中删除:
        mapObject.erase (lowerBound, upperBound); 

*/
#include <iostream>
#include <map>
#include <string>
using namespace std;

template <typename T>
void DisplayContents (const T& input)
{
    for (auto iElement = input.cbegin()
        ; iElement != input.cend()
        ; ++iElement)
    {
        cout << iElement->first << " points to "
            << iElement->second << endl;
    }
    cout << endl;
    
}

int main()
{
    multimap <int, string> mmapIntToString;
    mmapIntToString.insert(make_pair(3, "Three"));
    mmapIntToString.insert(make_pair(45, "Forty five"));
    mmapIntToString.insert(make_pair(-1, "Minus one"));
    mmapIntToString.insert(make_pair(1000, "One thousand"));

    mmapIntToString.insert(make_pair(-1, "Minus one(two)"));
    mmapIntToString.insert(make_pair(1000, "One Thousand(two)"));
    
    cout << "The multimap contains " << mmapIntToString.size();
    cout << " key-value pairs. " << "They are: " << endl;
    DisplayContents(mmapIntToString);

    auto NumPairsErased = mmapIntToString.erase(-1);
    cout << "Erased " << NumPairsErased << " pairs with -1 as key." << endl;

    auto iPairLocator = mmapIntToString.find(45);
    if(iPairLocator != mmapIntToString.cend())
    {
        mmapIntToString.erase(45);
        cout << "Erased a pair with 45 as key using an iterator" << endl;
    }
    
    cout << "Erasing the range of pairs with 1000 as key." << endl;
    mmapIntToString.erase(mmapIntToString.lower_bound(1000),
                        mmapIntToString.upper_bound(1000));
    
    cout << "The multimap now contains " << mmapIntToString.size();
    cout << " key-value pair(s)." << "They are:" << endl;
    DisplayContents(mmapIntToString);
    system("pause");
    return 0;
}

关于lower_bound() 和 upper_bound() ?

自定义的谓词排序

要提供不同的排序标准,可编写一个二元谓词 ——> 实现了 operator( ) 的类或结构:

template<typename keyType> 
struct Predicate 
{ 
     bool operator()(const keyType& key1, const keyType& key2) 
     { 
     // your sort priority logic here 
     } 
};

// 声明map
map <keyType, valueType, Predicate> mapObject;

对于键类型为 std::string 的 map,默认排序谓词 std::less 导致根据 std::string 类定义的 < 运算符进行排序,因此区分大小写。一种解决方案是在实例化 map 时提供一个排序谓词,根据不区分大小写的比较结果返回 true 或 false,如下所示:

#include <iostream>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
template <typename T>
void DisplayContents (const T& input)
{
    for (auto iElement = input.cbegin()
        ; iElement != input.cend()
        ; ++iElement)
    {
        cout << iElement->first << " points to "
            << iElement->second << endl;
    }
    cout << endl;
    
}

struct IgnoreCase
//class IgnoreCase
{
//public:
    bool operator()(const string& str1, const string& str2) const
    {
        string str1NoCase(str1), str2NoCase(str2);
        transform(str1.begin(), str1.end(), str1NoCase.begin(), ::tolower);
        transform(str2.begin(), str2.end(), str2NoCase.begin(), ::tolower);
        return (str1NoCase < str2NoCase);
    }
};

typedef map <string, string> DIRECTORY_WITHCASE;
typedef map <string, string, IgnoreCase> DIRECTORY_NOCASE;

int main()
{
    DIRECTORY_NOCASE dirCaseInsensitive;
    dirCaseInsensitive.insert(make_pair("John", "2345764"));
    dirCaseInsensitive.insert(make_pair("JOHN", "2345764"));
    dirCaseInsensitive.insert(make_pair("Sara", "42367236"));
    dirCaseInsensitive.insert(make_pair("Jack", "32435348"));
    cout << "Displaying contents of the case-insensitive map: " << endl;
    DisplayContents(dirCaseInsensitive);

    DIRECTORY_WITHCASE dirCaseSensitive(dirCaseInsensitive.begin(), 
                                        dirCaseInsensitive.end());
    cout << "Displaying contents of the case-sensitive map: " << endl;
    DisplayContents(dirCaseSensitive);

    cout << "Please enter a name to search: " << endl << "> ";
    string strNameInput;
    cin >> strNameInput;

    auto iPairInNoCaseDir = dirCaseInsensitive.find(strNameInput);
    if (iPairInNoCaseDir != dirCaseInsensitive.cend())
    {
        cout << iPairInNoCaseDir->first << "'s number in the case-insensitive";
        cout << " directory is: " << iPairInNoCaseDir->second << endl;
    }
    else
    {
        cout << strNameInput << "'s number not found ";
        cout << "in the case-insensitive directory"  << endl;
    }

    auto iPairInCaseSensDir = dirCaseSensitive.find(strNameInput);
    if (iPairInCaseSensDir != dirCaseSensitive.cend())
    {
        cout << iPairInCaseSensDir->first << "'s number in the case-sensitive";
        cout << " directory is: " << iPairInCaseSensDir->second << endl;
    }
    else
    {
        cout << strNameInput << "'s number was not found ";
        cout << "in the case-sensitive directory" << endl;
    }
    system("pause");
    return 0;
}

也可以将结构 PredIgnoreCase 声明为类,此时需要给 operator( ) 加上关键字 public。

std::map 的查找性能虽然比 vector、list 高,但其查找速度会随着元素的增加而降低,所需时间与 map 包含元素对数成正比。

unordered_map、unordered_multimap

此类是基于散列表

平均插入和删除时间是固定的,查找元素的时间也是固定的。

头文件:#include <unordered_map>

调用 find() 时会根据键查找元素,需要调用以下函数根据键来计算索引:

Index = HashFunction(key, TableSize);

初始化、查找、插入等操作与map等相同。需要注意的是 unordered_map 包含包含一个散列函数,用于计算排列顺序:

unordered_map<int, string>::hasher hFn = umapIntToStr.hash_function(); 
size_t hashingVal = hFn(1000);
// 在元素数达到或接近桶数时,它将自动执行负载均衡:

// load_factor( ) 指出了 unordered_map 桶的填满程度
cout << "Load factor: " << umapIntToStr.load_factor() << endl; 

// load_factor( ) 超过max_load_factor( )时,unordered_map 将重新组织以增加桶数,并重建散列表
cout << "Max load factor = " << umapIntToStr.max_load_factor() << endl; 

// 桶数量
cout << "Max bucket count = " << umapIntToStr.bucket_count() << endl;

具体实例:

#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
template <typename T1, typename T2>
void DisplayUnorderedMap (unordered_map<T1, T2>& Input)
{
    cout << "Number of pairs, size(): " << Input.size() << endl;
    cout << "Bucket count: " << Input.bucket_count() << endl;
    cout << "Load factor: " << Input.load_factor() << endl;
    cout << "Max load factor: " << Input.max_load_factor() << endl;

    for (auto iElement = Input.cbegin(); iElement != Input.cend(); ++iElement)
    {
        cout << iElement->first << " -> " << iElement->second << endl;
    }
    cout << endl;
}

int main()
{
    unordered_map <int, string> umapIntToStr;
    umapIntToStr.insert(make_pair(1, "One"));
    umapIntToStr.insert(make_pair(45, "Forty five"));
    umapIntToStr.insert(make_pair(1001, "Thousand one"));
    umapIntToStr.insert(make_pair(-2, "Minus Two"));
    umapIntToStr.insert(make_pair(-1000, "Minus One Thousand"));
    umapIntToStr.insert(make_pair(100, "One Hundred"));
    umapIntToStr.insert(make_pair(12, "Twelve"));
    umapIntToStr.insert(make_pair(-100, "Minus One Hundred"));

    DisplayUnorderedMap<int, string>(umapIntToStr);
    cout << endl;
    /*
    	Number of pairs, size(): 8
        Bucket count: 17
        Load factor: 0.470588
        Max load factor: 1
        -100 -> Minus One Hundred
        12 -> Twelve
        45 -> Forty five
        -1000 -> Minus One Thousand
        1 -> One
        -2 -> Minus Two
        1001 -> Thousand one
        100 -> One Hundred
    */

    cout << "Inserting one more element:" << endl;
    umapIntToStr.insert(make_pair(300, "Three handred"));
    DisplayUnorderedMap<int, string>(umapIntToStr);
    cout << endl;
    /*
    	Inserting one more element:
        Number of pairs, size(): 9
        Bucket count: 17
        Load factor: 0.529412
        Max load factor: 1
        -100 -> Minus One Hundred
        12 -> Twelve
        300 -> Three handred
        45 -> Forty five
        -1000 -> Minus One Thousand
        1 -> One
        -2 -> Minus Two
        1001 -> Thousand one
        100 -> One Hundred
    */
    
    cout << "Enter key to find for: ";
    int key = 0;
    cin >> key; // 300

    auto iElementFound = umapIntToStr.find(key);
    if (iElementFound != umapIntToStr.end())
    {
        cout << "Found key " << iElementFound->first << " points to value: ";
        cout << iElementFound->second << endl;
    }
    else
    {
        cout << "Key has no corresponding value in unordered map!" << endl;
    }
    // Enter key to find for: Found key 300 points to value: Three handred
    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值