20、关联容器、无序容器
- 关联容器
- map
- multimap
- set
- multiset
- 无序容器
- 哈希
- unordered_map
关联容器
map
// map的使用
#include <iostream>
#include <map>
#include <stdexcept>
using namespace std;
class Student{
public:
Student(const string& name="", int age=0):m_name(name),m_age(age){}
private:
string m_name;
int m_age;
friend ostream& operator<<(ostream& os, const Student& stu);
};
ostream& operator<<(ostream& os, const Student& stu){
return os << stu.m_name << ',' << stu.m_age;
}
void print(map<string,Student>& m){
typedef map<string,Student>::iterator IT;
for(IT it = m.begin(); it != m.end(); ++it){
cout << (*it).first << ':' << (*it).second << endl;
}
cout << "-----------------" << endl;
}
int main(void){
// 创建map
// 1. 创建空的map
// map<string, Student> m1;
// 2. 使用初始化列表指定初始值
map<string,Student> m2{
{"1005",{"张飞",25}},
{"1002",{"赵云",27}},
{"1010",{"关羽",30}}
};
/* print(m2);
// 3. 用现有容器创建
map<string,Student> m3{m2};
print(m3);
map<string,Student> m4{++m2.begin(), --m2.end()};
print(m4);*/
// 插入
m2.insert(pair<string,Student>("1001",Student("刘备",40)));
m2.insert(make_pair("1011",Student("诸葛亮",35)));
m2.insert({{"1007",Student("周瑜",28)},{"1003",Student("马超",30)}}); // key存在:什么也不做 key不存在:插入
m2["1011"] = Student("司马懿",36); // key存在:修改 key不存在:插入
print(m2);
// 访问
typedef map<string,Student>::reverse_iterator RIT;
RIT rit = m2.rbegin();
cout << "---------使用迭代器获取元素----------" << endl;
cout << (*rit).first << ':' << (*rit).second << endl;
cout << "---------使用键获取对应的值-----------" << endl;
// Student stu = m2["1006"]; // key存在:返回值 key不存在:添加
try{
Student stu = m2.at("1006");
}
catch(out_of_range& e){
cerr << e.what() << endl;
cout << "不存在学号为1006的学生" << endl;
}
print(m2);
// 删除
cout << "---------根据key删除-----------" << endl;
if(m2.erase("1006"))
cout << "1006被删除" << endl;
else
cout << "1006不存在" << endl;
typedef map<string,Student>::iterator IT;
cout << "---------根据迭代器删除-----------" << endl;
IT it = m2.erase(m2.begin());
if(it == m2.end())
cout << "最后一个元素被删除" << endl;
else
cout << "位于" << it->first << "前面的元素被删除" << endl;
print(m2);
// 查找
IT fit = m2.find("1007");
if(fit == m2.end())
cout << "1007不存在" << endl;
else
cout << "找到1007:" << fit->second << endl;
return 0;
}
multimap
- 允许键重复的映射,表示一对多的逻辑关系,不支持下标运算符
- 定义形式: multimap<键类型,值类型>映射对象
- 头文件: map
// multimap的使用
#include <iostream>
#include <map>
using namespace std;
int main(void){
multimap<string,int> m;
m.insert(pair<string,int>("zhangfei",88));
m.insert(make_pair("zhaoyun",85));
m.insert({{"guanyu",70},{"liubei",80}});
m.insert(pair<string,int>("zhangfei",67)); // 键允许重复
m.insert(make_pair("zhaoyun",76));
/*
typedef multimap<string,int>::iterator IT;
for(IT it=m.begin(); it!=m.end();++it)
cout << (*it).first << ':' << (*it).second << endl;
*/
for(const auto& p : m)
cout << p.first << ':' << p.second << endl;
// cout << m["zhangfei"] << endl; // error multimap不支持下标
return 0;
}
set
- 没有值只有键的映射
- 与向量等基本容器相比最大优势就是 排重
- 定义形式:
set<T>
集合对象 - 头文件:
set
// set的使用
#include <iostream>
#include <set>
using namespace std;
int main(void){
set<int> s;
s.insert(1);
s.insert(10);
s.insert(2);
s.insert(1);
s.insert(10);
s.insert(2);
s.insert(12);
s.insert(8);
s.insert(6);
cout << "元素数:" << s.size() << endl; // 6: set中的元素不允许重复
for(int i: s)
cout << i << ' ';
cout << endl;
return 0;
}
multiset
- 没有值只有键的多重映射。
- 定义形式:
multiset<T>
多重集合对象 - 头文件:
set
// multiset的使用
#include <iostream>
#include <set>
using namespace std;
int main(void){
multiset<int> s;
s.insert(1);
s.insert(10);
s.insert(2);
s.insert(1);
s.insert(10);
s.insert(2);
s.insert(12);
s.insert(8);
s.insert(6);
cout << "元素数:" << s.size() << endl; // 9: multiset中的元素允许重复
for(int i: s)
cout << i << ' ';
cout << endl;
return 0;
}
无序容器
哈希
定义
- 哈希是用给定范围的基本类型的数据项,或者类似string这样的对象,生成整数值的过程
- 哈希产生的值叫做哈希值或者哈希码,通常用在容器中,用来确定表中对象的位置
- 理想情况下,每个对象产生的哈希值是唯一的,但实际是可能产生重复的。重复的哈希值称为哈希碰撞
//哈希函数
hash<Key>
template<typename Key> struct hash{}
//成员函数
size_t operator()(Key k){}
unordered_map
// unordered_map
#include <iostream>
#include <unordered_map>
using namespace std;
class Name{
public:
Name(const string& forename="",const string& surname=""):m_forename(forename),m_surname(surname){}
bool operator==(const Name& that)const{
return m_forename==that.m_forename && m_surname == that.m_surname;
}
private:
string m_forename; // 姓
string m_surname; // 名
friend ostream& operator<<(ostream& os, const Name& name);
friend class NameHash;
friend class NameEqual;
};
ostream& operator<<(ostream& os, const Name& name){
return os << name.m_forename << name.m_surname;
}
// 哈希类
class NameHash{
public:
size_t operator()(const Name& name)const{
hash<string> hs;
return hs(name.m_forename)^(hs(name.m_surname)<<1);
}
};
// 判等类
class NameEqual{
public:
bool operator()(const Name& a,const Name& b)const{
return a.m_forename == b.m_forename && a.m_surname == b.m_surname;
}
};
int main(void){
unordered_map<Name,int,NameHash/*,NameEqual*/> um{
{{"zhang","fei"},88},{{"zhao","yun"},85},{{"guan","yu"},90}
};
for(const auto& p : um)
cout << p.first << ":" << p.second << endl;
/*
unordered_map<string,int> um{
{"zhangfei",88},{"zhaoyun",85},{"guanyu",90}
};
cout << um["zhaoyun"] << endl;
hash<string> hs; // 哈希器
for(const auto& p : um)
cout << p.first << "(" << hs(p.first) << ")" << " :" << p.second << endl;
*/
return 0;
}