关联容器:对象的位置取决于和它关联的键的值。键可以是基本类型,也可以是类类型。
map<K,T> 类模板:定义了一个保存 T 类型对象的 map,每个 T 类型的对象都有一个关联的 K 类型的键。容器内对象的位置是通过比较键决定的,唯一的要求是键必须可以用 less<K> 比或用自己指定的另一个函数对象来替代。
类模板键:
图 表示的是 map<Name,size_t> 类型的容器,其中的 Name 类可以这样定义:
class Name
{
private:
std::string firstname{}; std::string secondname{};
public:
Name(std::string first, std::string second) : firstname{first}, secondname{second}{};
Name()=default;
bool operator<(const Name& name)
{
return secondname < name.secondname ||((secondname == name.secondname) && (firstname < name.firstname));
}
};
std::map<std::string, size_t> people;
std::map<std::string, size_t> people{{"Ann", 25}, {"Bill", 46},{"Jack", 32},{"Jill", 32}};
//2
std::map<std::string,size_t> people{std::make_pair("Ann",25),std::make_pair("Bill", 46),std::make_pair("Jack", 32),std::make_pair("Jill", 32)};
//3
std::map<std::string, size_t> personnel {people};
std::map<std::string, size_t> personnel {std::begin(people),std::end(people)};
//用另一个容器的元素子集来创建容器
std::map<std::string,size_t> personnel {++std::begin(people),std::end(people)};
必须要求:只能插入 map 中不存在的元素。
std::map<std:: string,size_t> people {std::make_pair ("Ann",25),std::make_pair("Bill",46) , std::make_pair ("Jack",32), std::make_pair("Jill",32)};
auto pr = std::make_pair("Fred",22); //Create a pair element and insert it
auto ret_pr = people.insert(pr);
std::cout << ret_pr.first->first << " "<< ret_pr.first->second<< "" << std:: boolalpha <<ret_pr.second << "\n"; // Fred 22 true
成员函数 insert() :返回一个 pair<iterator,bool> 对象。对象的成员 first 是一个迭代器,它要么指向插入元素,要么指向阻止插入的元素。如果 map 中已经保存了一个和这个键相同的对象,就会出现后面这种情况。这个对象的成员变量 second (布尔型)是返回对象,如果插入成功,返回值为 true,否则为 false。
2.1循环访问
for (const auto& p : people)
std::cout << std::setw(10) << std::left << p.first << " "<< p.second <<"\n";
Ann 25
Bill 46
Fred 22
Jack 32
Jill 32
元素是以键的升序排列的,因为 map 中默认使用 less<string> 进行排序。
2.2插入相同元素
ret_pr = people.insert(std::make_pair("Bill", 48));
ret_pr = people.insert(std::pair<const std::string, size_t> {"Bill", 48}
std:: cout << ret_pr.first->first <<" "<<ret_pr.first->second<< " "<<std::boolalpha<<ret_pr.second << "\n"; // Bill 46 false
insert() 返回了一个 pair 对象 ret_pr,它的成员变量 first 指向 map 中已有的和键匹配的元素,成员变量 second 为 false,表明元素没有插入成功。
键值“Bill”对应的年龄值改为 48:
if(!ret_pr.second) // If the element is there change the age
ret_pr.first—>second = 48;
2.3提供一个提示符来指出元素插入的位置
auto ret_pr = people.insert(std::make_pair("Jim", 48));
people.insert (ret_pr.first, std::make_pair ("Ian", 38))
insert() 的第二个参数指定的新元素会被插入到提示符的前面,并尽可能地靠近它
如果被插入的元素已经在 map 中,会导致元素插入失败
确定元素不存在时,可以只提供一个插入符;如果不那么确定,而且仍然想使用插入符,map 中的 count() 函数会返回 map 中指定键对应元素的数目,这个数目可能是 0 或 1。
if (!people.count("Ian"))
people.insert (ret_pr.first, std::make_pair ("Ian", 38));
当 count() 函数返回 0 时,insert() 才会被调用,这说明“Ian”键不在 map 中。
2.4外部源中的一段元素插入 map
这些元素不必来自另一个 map 容器,但必须和被插入容器中的元素是同类型。
std::map<std::string, size_t> crowd {{"May", 55}, {"Pat",66}, {"Al", 22}, {"Ben", 44}};
auto iter = std::begin(people);
std::advance(iter, 4); // begin iterator+ 4
crowd.insert(++std::begin(people),iter); // Insert 2nd, 3rd, and 4th elements from people
2.5接受初始化列表作为参数的 insert() 版本:
crowd.insert({{"Bert", 44}, {"Ellen”, 99}});
也可以单独创建一个初始化列表,然后将它作为参数传递给 insert() 函数:
std::initializer_list<std::pair<const std:: string, size_t>>init {{"Bert", 44}, {"Ellen", 99}};
crowd.insert(init);
#ifndef NAME_H
#define NAME_H
#include <ostream>
#include <istream>
class Name
{
private:
std::string first {};
std::string second {};
public:
Name(const std::string& name1, const std::string& name2) : first (name1), second (name2) {}
Name() = default;
bool operator<(const Name& name) const
{
return second < name.second || (second == name.second && first < name.first);
}
friend std::istream& operator>>(std::istream& in, Name& name);
friend std::ostream& operator<<(std::ostream& out, const Name& name);
};
inline std::istream& operator>>(std::istream& in, Name& name)
{
in >> name.first >> name.second;
return in;
}
inline std::ostream& operator<<(std::ostream& out, const Name& name)
{
out << name.first + " " + name.second;
return out;
}
#endif
map 容器中的元素是 std::pair<const Name,size_t> 类型,可以用下面定义的别名来简化代码:
using Entry = std::pair<const Name, size_t>;
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <utility> // For pair<> & make_pair<>()
#include <cctype> // For toupper()
#include "name.h"
using std::string;
using Entry = std::pair<const Name, size_t>;
using std::make_pair;
using std::map;
// Create a map entry from input
Entry get_entry()
{
std::cout << "Enter first and second names followed by the age: ";
Name name {};
size_t age {};
std::cin >> name >> age;
return make_pair(name, age);
}
// Output the elements in a map
void list_entries(const map<Name, size_t>& people)
{
for(auto& entry : people)
{
std::cout << std::left << std::setw(30) << entry.first
<< std::right << std::setw(4) << entry.second << std::endl;
}
}
int main()
{
map<Name, size_t> people {{{"Ann", "Dante"}, 25}, {{"Bill", "Hook"}, 46},
{{"Jim", "Jams"}, 32}, {{"Mark", "Time"}, 32}};
std::cout << "\nThe initial contents of the map is:\n";
list_entries(people);
char answer {'Y'};
std::cout << "\nEnter a Name and age entry.\n";
while(std::toupper(answer) == 'Y')
{
Entry entry {get_entry()};
auto pr = people.insert(entry);
if(!pr.second)
{ // It's there already - check whether we should update
std::cout << "Key \"" << pr.first->first <<
"\" already present. Do you want to update the age (Y or N)? ";
std::cin >> answer;
if(std::toupper(answer) == 'Y')
pr.first->second = entry.second;
}
// Check whether there are more to be entered
std::cout << "Do you want to enter another entry(Y or N)? ";
std::cin >> answer;
}
std::cout << "\nThe map now contains the following entries:\n";
list_entries(people);
}
结果显示: