Map容器

Posted alexkk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Map容器相关的知识,希望对你有一定的参考价值。

map容器

是关联容器的一种,由键值对象组成,即 map 容器的元素是 pair<const K,T> 类型的对象

map容器的类型

  1. map<K,T>容器,保存的是 pair<const K,T> 类型的元素。pair<const K,T> 封装了一对键对象,键的类型是 K,对象的类型是 T。每个键都是唯一的,所以不允许有重复的键;但可以保存重复的对象,只要它们的键不同。map 容器中的元素都是有序的,元素在容器内的顺序是通过比较键确定的。默认使用 less 对象比较。

  2. multimap<K,T> 容器和 map<K,T> 容器类似,也会对元素排序。它的键必须是可比较的,元素的顺序是通过比较键确定的。和 map<K,T> 不同的是,multimap<K,T> 允许使用重复的键。因此,一个 multimap 容器可以保存多个具有相同键值的 <const K,T> 元素。

  3. unordered_map<K,T> 中 pair< const K,T>元素的顺序并不是直接由键值确定的,而是由键值的哈希值决定的。哈希值是由一个叫作哈希的过程生成的整数,本章后面会解释这一点。unordered_map<K,T>不允许有重复的键。

  4. unordered_multimap<K,T> 也可以通过键值生成的哈希值来确定对象的位置,但它允许有重复的键。

区别

  • multi前缀表明键不必唯一,但如果没有这个前缀,键必须唯一。
  • unordered_prefix 前缀表明容器中元素的位置是通过其键值所产生的哈希值来决定的,而不是通过比较键值决定的。如果没有该前缀,那么元素的位置就由比较键值决定。

头文件

#include<map>
#include<unorderd_map>

map的创建和初始化

1 创建

//map<K,T>
map<string, size_t> people;

map默认构造函数有四个参数,但常常只初始化前两个参数,用于构造pair对象,因为map容器里面的对象都是pair<string,size_t>,string 说明了键的类型,size_t说明了值的类型,可以通关first和second访问第一个值和第二个值

2 初始化

2.1 初始化列表,隐式的转化为pair对象

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};

2.2 make_pair显示的构造pair对象初始化

map<string,size_t> people{make_pair("Ann",25),make_pair("Bill", 46),make_pair("Jack", 32),make_pair("Jill", 32)};

2.3 容器拷贝

map<string,size_t> peopelCopy {people};
//类型必须一致

2.4 迭代器初始化

map<string,size_t>peopleCopy2{people.begin(),people.end()}

代码实例

int main()
{
    map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
    map<string, size_t> peopleCopy{people.begin(), people.end()};
    for(auto &i:peopleCopy)
    {
        cout << i.first << " "<<i.second<<endl;
    }
    return 0;
}

3 Insert插入元素

3.1 初始化列表插入

由于map默认是按照less从小到大排序的,因此插入不指定插入位置。

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
people.insert({"Hon",3});

3.2 make_pair构造pair对象插入

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
auto pr = make_pair("Hon",3);
auto ret_pr = people.insert(pr);

说明:

1 make_pair返回值是一个pair对象

2 insert的返回值仍然是一个pair对象, pair 的成员变量 first 是一个指向插入元素或阻止插入的元素的迭代器;成员变量 second 是个布尔值,如果元素插入成功,second 就为 true。

cout<<ret_pr.first->first<<" "<<ret_pr.first->second<<endl;
cout<<ret_pr.second<<endl;
//Hon 3
//True

3.3 直接使用pair对象插入,右值移动

people.insert(pair<string,size_t>{"Hon", 3});

4 emplace构造元素

4.1emplace

emplace和insert的区别在于 emplace可以在适当的位置直接构造新元素,从而避免复制和移动操作,返回值同insert。

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
auto ret_pr = people.emplace("Kiss",9);

4.2 emplace_hint

emplace_hint() 调用使用一个迭代器作为指示符,指向先前 emplace() 调用返回的 pair 对象。如果容器使用这个提示符,那么新元素会在这个指示符表示的位置之前生成,并尽可能靠近这个位置。提示符后面的参数用来构造新元素。需要注意的是,它和 emplace() 的返回值是不一样的。emplace_hint() 的返回值不是一个 pair 对象,如果新元素被插入,它返回的是指向新元素的迭代器;如果没有插入,返回的是和这个键匹配的现有元素的迭代器,拥有相同的 key 值,如果不是现有元素的话。没有提示可以直接判断是否生成了新元素。唯一的方法是,用 size() 成员函数来获取 map 中对应元素的数量来检查 map 元素增加的数量

auto pr = people.emplace("Kiss",9);
auto iter = people.emplace_hint (pr.first,"Gine", 62);

5 map元素访问

5.1 迭代器

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
auto it = people.begin();
while (it != people.end())
{
    cout << (*it).first << " " << (*it).second << endl;
    it++;
}

5.2 at(key)

由于at()一般会检查边界,因此要对key做异常处理

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
string key;
try
{
    key = "Anni";
    cout << people.at(key) << endl;
    key = "Ai";
    cout << people.at(key) << endl;
}
catch (const out_of_range &e)
{
    cerr << e.what() << endl;
}
-------------------------------------
12
invalid map<K,T> key

5.3 [key]

下标运算符返回一个和 键关联的对象的引用,如果key指定的对象不存在,创建一个pair对象,值为0

cout<<people["Anni"]<<endl;
cout<<people["Ai"]<<endl;
---------------------------
12
0

由于[key]返回的是引用,因此可以通过=修改key对应的值

people["Ai"]=2;
cout<<people["Ai"]<<endl;
-----------------------
2

6 erase/clear 删除元素

6.1 erase(key)

键作为参数传递,erase 返回值是删除元素的个数,如果没有对应key返回0,否则返回1

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
string key{"Anni"};
if(people.erase(key))
	cout<<"erase success"<<endl;
else
	cout<<key<<"was not found"<<endl;
auto it = people.begin();
while (it != people.end())
{
    cout << (*it).first << " " << (*it).second << endl;
    it++;
}
-----------------------
erase success
Joe 20
Bob 10

6.2 erase(iteration)

迭代器作为参数,返回值为迭代器,返回的迭代器指向被删除元素的下一个位置(注意是排好序的),

如果删除元素是最后一个元素,返回的迭代器指向最后一个元素。

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
auto it = people.begin();
auto pr = people.erase(it);
cout << (*pr).first <<" " << (*pr).second<< endl;
-----------------------------------------
Bob 10 //注意排序

还可以删除迭代器指定范围内的元素 erase(start_iter,end_iter);

6.3 clear()

删除所有元素

map<string,size_t> people{{"Anni",12},{"Joe",20},{"Bob",10}};
cout<<people.size()<<endl;
people.clear()
cout<<people.size()<<endl;
--------------------------
3
0

Pair

头文件:pair是包含在头文件utility中的,map头文件又包含了utility

#inclue<utility>
或者
#include<map>

part<T1,T2> ,T1,T2可以是任意类型

pair<int,int> p1{10,6}
pair<string,int> p2{"anni",5}
pait<TreeNode,bool> p3{root,false}
...

make_pair

auto mypair = make_pair("hello","boy");
auto youPair = make_pair<string,sting>("test","that");
.....

Tuple

tuple是pair的泛化,不仅包含两个类型的对象,当要把多个对象作为一个对象传递给函数时,tuple很有用:生成一个tuple对象使用:make_tuple

#include<tuple>
auto my_tuple = make_tuple("name",42,"address",667,..);

以上是关于Map容器的主要内容,如果未能解决你的问题,请参考以下文章

android google map supportmap片段无法在片段中初始化

将Android片段移动到不同的容器无法更改片段的容器ID

比较有用的php代码片段

JavaScript 代码片段

代码片段 - Golang 实现集合操作

如何在 Android 中的特定片段容器中显示片段