map和multimap
开始
- c++有map和multimap两种容器,区别在于multimap允许重复元素,map则不允许,在头文件中< map >中定义
- Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字(key),每个关键字只能在map中出现一次,第二个可能称为该关键字的值(value))的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的
</div>
它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。
自动建立Key - value的对应。key 和 value可以是任意你需要的类型。 根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
什么是一对一的数据映射。比如一个班级中,每个学生的学号跟他的姓名就存在着一一映射的关系,这个模型用map可能轻易描述,很明显学号用int描述,姓名用字符串描述,下面给出map描述代码:
1
| map<int, string> mapStudent;
|
声明初始化
1 2 3 4 5 6 7 8 9 10
| #include<map>
map<int, string> ID_Name; map<int, string, op>;
map<int, string> ID_Name = { { 2015, "Jim" }, { 2016, "Tom" }, { 2017, "Bob" } };
|
插入操作
使用数组方式插入
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream> #include <map> using namespace std; int main() { map<int, string> mymap; mymap[10] = "hello"; cout << mymap.begin()->first << mymap.begin()->second;
return 0; }
|
使用insert进行单个和多个插入
插入单个键值对
1 2
| pair<iterator,bool> insert (const value_type& val);
|
一个简单的栗子,使用插入功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> #include <map> using namespace std;
int main() { ios::sync_with_stdio(false); map<string, int>mymap; mymap.insert(pair<string, int>("hello world", 2010)); auto iter = mymap.begin(); while(iter != mymap.end()) { cout << iter->first << " "; cout << iter->second; iter++; } return 0; }
|
使用返回值的判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> #include <map> using namespace std;
int main() { ios::sync_with_stdio(false);
map<string, int>mymap; mymap.insert(pair<string, int>("hello world", 2010));
pair<map<string, int>::iterator, bool> ret; ret = mymap.insert(pair<string, int>("hello", 500)); if (ret.second == false) cout << "already existed"; else { cout << ret.first->first << " "; cout << ret.first->second ; }
return 0; }
|
下面是插入相同的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream> #include <map> using namespace std;
int main() { ios::sync_with_stdio(false);
map<string, int>mymap; mymap.insert(pair<string, int>("hello world", 2010));
pair<map<string, int>::iterator, bool> ret; ret = mymap.insert(pair<string, int>("hello world", 500)); if (ret.second == false) cout << "already existed"; else { cout << ret.first->first << " "; cout << ret.first->second ; }
return 0; }
|
可见,key或value与map里面已经存在的内容相同的话,就会不能插入
在指定位置插入
1 2
| iterator insert (const_iterator position, const value_type& val);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> #include <map> using namespace std;
int main() { ios::sync_with_stdio(false);
map<string, int>mymap; mymap.insert(pair<string, int>("hello world", 2010));
map<string, int>::iterator it = mymap.begin() ; mymap.insert(it, pair<string, int>("good morning, ", 300)); auto iter = mymap.begin(); while(iter != mymap.end()) { cout << iter->first << " "; iter++; } return 0; }
|
插入多个
1
| void insert (InputIterator first, InputIterator last);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> #include <map> using namespace std; int main() { std::map<char, int> mymap;
mymap.insert(pair<char, int>('a', 100)); mymap.insert(pair<char, int>('z', 200)); mymap.insert(pair<char, int>('b', 300)); mymap.insert(pair<char, int>('c', 400));
std::map<char, int> anothermap; anothermap.insert(mymap.begin(), mymap.find('z'));
auto iter = anothermap.begin(); while(iter != anothermap.end()) { cout << iter->first; iter++; } return 0; }
|
列表插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <iostream> #include <map> using namespace std; int main() { std::map<char, int> mymap; mymap.insert({{'a', 100}, {'b', 200}}); auto iter = mymap.begin(); while(iter != mymap.end()) { cout << iter->first << iter->second << endl; iter++; } return 0; }
|
关于更多insert信息以及c++17定义的insert函数可以参考:
std::map::insert
取值
map中元素取值主要有at和[ ]两种操作,at会作下标检查,而[]不会。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include <map> using namespace std; int main() { map<int, string> mymap; mymap[10] = "hello"; mymap.at(2016) = "world"; cout << mymap[2017]; return 0; }
|
取key和value
1 2 3 4 5 6 7 8 9 10
| .... map<string, int>mymap; mymap.insert(pair<string, int>("hello world", 2010)); auto pos = mymap,begin(); cout << pos->first; cout << pos->second;
pos->first = "hello"; pos->second = 13;
|
注意:map提供了一种非常方便的方法让你改变元素的key
1 2 3 4
| coll["new_key"] = coll["old_key"];
coll.erase("old_key");
|
容量查询
1 2 3 4 5 6 7 8 9 10 11 12
| bool empty();
size_t size();
size_t max_size();
size_t count( const Key& key ) const;
|
迭代器
共有八个获取迭代器的函数: begin, end, rbegin,rend\ 以及对应的 cbegin, cend, crbegin,crend\。
二者的区别在于,后者一定返回 const_iterator,而前者则根据map的类型返回iterator 或者 const_iterator。const情况下,不允许对值进行修改。如下面代码所示:
1 2 3 4 5 6 7 8 9
| map<int,int>::iterator it; map<int,int> mmap; const map<int,int> const_mmap;
it = mmap.begin(); mmap.cbegin();
const_mmap.begin(); const_mmap.cbegin();
|
返回的迭代器可以进行加减操作,此外,如果map为空,则 begin = end。
删除交换
删除
删除一定范围内的元素
1 2
| iterator erase( const_iterator first, const_iterator last );
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> #include <map> using namespace std; int main() { map<int, string> mymap; mymap.insert(pair<int, string>(1,"asdf")); mymap.insert(pair<int, string>(2,"qwer")); mymap.insert(pair<int, string>(3,"zxcv")); mymap.erase(mymap.begin(), mymap.find(2)); auto iter = mymap.begin(); while(iter != mymap.end()) { cout << iter->first << " " << iter->second << endl; iter++; } return 0;
2 qwer 3 zxcv
|
删除迭代器指向位置的键值对
1 2
| iterator erase( iterator pos )
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> #include <map> using namespace std; int main() { map<int, string> mymap; mymap.insert(pair<int, string>(1,"asdf")); mymap.insert(pair<int, string>(2,"qwer")); mymap.insert(pair<int, string>(3,"zxcv")); mymap.erase(mymap.find(2)); auto iter = mymap.begin(); while(iter != mymap.end()) { cout << iter->first << " " << iter->second << endl; iter++; } return 0; }
1 asdf 3 zxcv
|
根据Key来进行删除
1 2
| size_t erase( const key_type& key );
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <map> #include <string> #include <iostream> using namespace std;
int main() { map<int, string>mymap; mymap.insert(pair<int, string>(1,"hello")); mymap.insert(pair<int, string>(2,"wolrd")); mymap.erase(1); auto iter = mymap.begin(); while(iter != mymap.end()) { cout << iter->first << iter->second << endl; iter++; } return 0; }
|
清空map
交换
1 2
| void swap( map& other );
|
查找
1 2 3 4
|
iterator find (const key_type& k); const_iterator find (const key_type& k) const;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <map> #include <string> #include <iostream> using namespace std;
int main() { map<char,int> mymap; mymap['a']=50; mymap['b']=100; mymap['c']=150; mymap['d']=200;
auto it = mymap.find('b'); if(it != mymap.end()) mymap.erase (it); auto iter = mymap.begin(); while(iter != mymap.end()) { cout << iter->first << iter->second << endl; iter++; } return 0; }
a50 c150 d200
|
参考:
c++常见用法说明
multimap的一些注意事项
用erase删除重复元素的第一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <iostream> #include <map> using namespace std;
int main() { multimap<int, char>mymap; mymap.insert(make_pair(1,'a')); mymap.insert(make_pair(2,'b')); mymap.insert(make_pair(3,'c')); mymap.insert(make_pair(2,'a')); mymap.insert(make_pair(1,'a'));
mymap.erase(mymap.find(2)); auto it = mymap.begin(); while(it != mymap.end()) { cout << it->first << it->second << endl; it++; } return 0; }
|
移除所有与x相等的元素
假如是是移除所有与x相等的key值,可以像上面用erase,如果是value值,则看下面:
错误做法(c++11之前):
在C++11中,erase返回下一个迭代器,但之前的版本都返回void
1 2 3 4 5 6
| multimap<int, char>mymap; for(auto iter = mymap.begin(); iter != mymap.end(); iter++) { if(iter->second == value) mymap.erase(iter); }
|
对iter所指元素施加erase(),会使pos不再成为一个有效的mymap迭代器。
正确做法(c++11之前):
1 2 3 4 5 6 7 8
| multimap<int, char>mymap; for(auto iter = mymap.begin(); iter != mymap.end(); ) { if(iter->second == value) mymap.erase(iter++); else ++iter; }
|
iter++会将iter移向下一个元素,但返回其原始值(指向原位置)的一个副本。因此,当erase()被调用时,iter已经不再指向那个即将被移除的元素了。