详解map容器的使用
map是STL的一个关联容器,它提供一对一
的数据处理能力. 也就是内部存储的有两个部分,一个是固定的键值(从开始插入后就不
会再改变的值)也可以称为关键字另外一个是记录该关键字的状态(大小,翻译,对应关系).所以map的作用很广泛,生活中一一对
应
的东西太多了,比如你的身份证号和你,比如你需要记录很多不同东西的数量,还有很多很多. 而且map还是有序的.应用场景相
当
广泛. 但是map也是有不能存储的数据 只要该数据不能够互相比较大小那么就不能使用map存储. 那么为什么呢?
这里是由于map容器底层是使用搜索树来存储数据的,所以你在构建搜索树的时候需要不停的比较大小,这就是原因.而这里使用的搜
索树是较为成熟的红黑树,正因为底层是红黑色所以
map的查找,删
除,插入的
效率都很高. 那么如果你还是不了解为什么,那么你
我们可以通过map的迭代器改变map的元素内容吗? 如果想要修正元素的键值,答案是不行的,因为Map元素的键值关系到map元素的排
列顺序.任意改变map元素键值将会严重破坏map组织.但如果想要修正元素的实值,答案是可以,因为map元素的实值并不影响map元素的
排列规则,因此,map iterator既不是一种consttant iterator,也不是一种mutable iterato
map拥有与list相同的某些性质: 当客户端对它进行元素新增操作或删除操作时,操作之前的所有迭代器,在操作完成之后都依然有效,当然
那个被删除元素迭代器必然是个例外.
map的成员函数
at
|
查找具有指定键值的元素。 |
begin | 返回一个迭代器,此迭代器指向映射中的第一个元素。 |
cbegin | 返回一个常量迭代器,此迭代器指向映射中的第一个元素。 |
cend | 返回一个超过末尾常量迭代器。 |
clear | 清除映射的所有元素。 |
count | 返回映射中其键与参数中指定的键匹配的元素数量。 |
crbegin | 返回一个常量迭代器,此迭代器指向反向映射中的第一个元素。 |
crend | 返回一个常量迭代器,此迭代器指向反向映射中最后一个元素之后的位置。 |
emplace | 将就地构造的元素插入到映射。 |
emplace_hint | 将就地构造的元素插入到映射,附带位置提示。 |
empty | 如果映射为空,则返回 true。 |
end | 返回超过末尾迭代器。 |
equal_range | 返回一对迭代器。 此迭代器对中的第一个迭代器指向 map 中其键大于指定键的第一个元素。 此迭代器对中的第二个迭代器指向 map 中其键等于或大于指定键的第一个元素。 |
erase | 从指定位置移除映射中的元素或元素范围。 |
find | 返回一个迭代器,此迭代器指向映射中其键与指定键相等的元素的位置。 |
get_allocator | 返回用于构造映射的 allocator 对象的副本。 |
insert | 将元素或元素范围插入到映射中的指定位置。 |
key_comp | 返回用于对映射中的键进行排序的比较对象副本。 |
lower_bound | 返回一个迭代器,此迭代器指向映射中其键值等于或大于指定键的键值的第一个元素。 |
max_size | 返回映射的最大长度。 |
rbegin | 返回一个迭代器,此迭代器指向反向映射中的第一个元素。 |
rend | 返回一个迭代器,此迭代器指向反向映射中最后一个元素之后的位置。 |
size | 返回映射中的元素数量。 |
swap | 交换两个映射的元素。 |
upper_bound | 返回一个迭代器,此迭代器指向映射中其键值大于指定键的键值的第一个元素。 |
value_comp | 检索用于对映射中的元素值进行排序的比较对象副本。 |
shrink_to_fit | 放弃额外容量。 |
size | 返回vector元素个数 |
swap | 交换两个向量的元素。 |
访问操作
这里我们需要熟练运用的函数为:at,begin,end,count,find.
map<int, int> T;
T[0] = 1;
T[1] = 2;
T[2] = 3;
T[3] = 4;
//operator[]返回指定下标的引用.
cout << "map容器中关键值为2的val为:";
cout << T.at(2) << endl;
//at函数查找输入键值对应的元素.
cout << "从头遍历该map元素" << endl;
map<int, int>::iterator it = T.begin();
//返回map中第一个元素位置的迭代器
while (it != T.end())
//返回map中最后一个元素下一个位置的迭代器
{
cout << it->first << " ->>> " << it->second << endl;
++it;
//让迭代器跳转到下一个元素的位置.
}
cout << "find一个元素的迭代器并且访问它:";
cout << T.find(3)->first << " ->>> " << T.find(3)->second << endl;
运行结果:
插入操作
插入的操作我们我们不是直接就把两个值传给他,我们需要先把两个放进pair里面,比如最基本的插入insert(pair<K,V>(key,val));
这里每次插入的时候都要给pair传入模板类型有点繁琐,所以我想着在这里封装一个函数让模板参数可以自动识别,所以写一个函数为
template<typename K, typename V>
pair<K, V> mymake_pair(const K& key,const V& val)
{
return pair<K, V>(key, val);
}
其实编译器有一个这个函数,但是我们也需要明白函数的底层构造以及为什么需要这个函数,接下来我们看几种不同的重载的插入:
map<int, int> T;
//***1*** 最正常的插入
T.insert(pair<int, int>(1, 1));
T.insert(pair<int, int>(2, 2));
T.insert(pair<int, int>(3, 3));
//这是最基本的插入操作,这里没有前插后插的,因为搜索树会负责给你安排位置
//这里不需要你操心.
T.insert(mymake_pair(4, 4));
T.insert(mymake_pair(5, 5));
T.insert(mymake_pair(6, 6));
map<int, int>::iterator it1 = T.begin();
cout << "遍历T中的元素:" << endl;
while (it1 != T.end())
{
cout << it1->second << " ";
cout << "的val为" << " ";
cout << it1->first << endl;
++it1;
}
cout << endl;
//***2** 利用迭代器进行区间插入
std::map<int, int> anothermap;
anothermap.insert(T.begin(), T.find(4));
//
map<int, int>::iterator it2 = anothermap.begin();
cout << "遍历anothermap中的元素:" << endl;
while (it2 != anothermap.end())
{
cout << it2->second << " ";
cout << "的val为 " << " ";
cout << it2->first << endl;
++it2;
}
运行结果:
删除操作
其实当你明白插入操作之后,我觉得删除操作,以及删除操作里面的删除迭代器区间的操作你会很容易就Get到. 我这里就直接撸代码了!
map<int, int> T;
T.insert(mymake_pair(1, 1));
T.insert(mymake_pair(2, 2));
T.insert(mymake_pair(3, 3));
T.insert(mymake_pair(4, 4));
T.insert(mymake_pair(5, 5));
T.insert(mymake_pair(6, 6));
map<int, int>::iterator it1 = T.begin();
cout << "遍历T中的元素:" << endl;
while (it1 != T.end())
{
cout << it1->second << " ";
cout << "的val为" << " ";
cout << it1->first << endl;
++it1;
}
cout << endl;
//***2*** 删除单个迭代器
map<int, int>::iterator it3 = T.find(2);
//通过find拿到关键字为2的迭代器
T.erase(it3);
//然后删除该元素.
it1 = T.begin();
cout << "遍历T中的元素:" << endl;
while (it1 != T.end())
{
cout << it1->second << " ";
cout << "的val为" << " ";
cout << it1->first << endl;
++it1;
}
cout << endl;
//***2*** 删除迭代器区间
it3 = T.find(3);
//通过find拿到关键字为3的迭代器
T.erase(it3, T.end());
//删除掉it3到map容器结束的所有节点.
it1 = T.begin();
cout << "遍历T中的元素:" << endl;
while (it1 != T.end())
{
cout << it1->second << " ";
cout << "的val为" << " ";
cout << it1->first << endl;
++it1;
}
cout << endl;
//***3*** 终极大招 删除所有元素.
T.insert(mymake_pair(1, 1));
T.insert(mymake_pair(2, 2));
T.insert(mymake_pair(3, 3));
T.insert(mymake_pair(4, 4));
T.insert(mymake_pair(5, 5));
T.insert(mymake_pair(6, 6));
T.clear();
//删除所有元素.
it1 = T.begin();
cout << "遍历T中的元素:" << endl;
while (it1 != T.end())
{
cout << it1->second << " ";
cout << "的val为" << " ";
cout << it1->first << endl;
++it1;
}
cout << endl;
运行结果:
其他操作
这里map也有和vector和list相似的其他功能,比如size,empty,swap...... 相信大家会用vector,list的功能就会使用map的这些功能.
如果不会使用也没关系! 详细vector的用法 以及 详细的list的用法 这两个博客我写了好久,功能也挺全的,不懂的可以顺便过去
瞧一瞧~ map其实挺好用的,最重要的是尝试自己实现一个Map,这样你的红黑树的理解,你的设计结构能力会有很高的进步.等我实
现ok,会再写一个博客的.