unordered_map、unordered_set使用
unordered_map
头文件
#include <iostream>
#include <unordered_map>
using namespace std;
增删查改
unordered_map底层实现为哈希表,增删效率与查找效率都是O(1)
增加元素
- emplace(key,value)
- insert(pair<T,T> p)
- 数组修改法
//unordered_map 三种增加元素的方式
// insert(pair)
// emplace(key,value)
// m[key] = value
#include <iostream>
#include <unordered_map>
using namespace std;
void showMap(unordered_map<int,int> &m){
unordered_map<int,int>::iterator it;
for(it=m.begin();it!=m.end();it++){
cout<<"key: "<<it->first<<", "<<"value: "<<it->second<<endl;
}
}
int main(int argc, char *argv[]){
unordered_map<int,int> m;
m.insert(make_pair(1,2));
m.insert(pair<int,int>(3,4));
m[2]=3;
m.emplace(4,5);
//测试已有键插入
//已有键:1,2,3,4
m.insert(make_pair(1,3));
m.emplace(4,2);
m[2] = 4;
showMap(m);
}
- 共同点:插入的都是键值对,区别只是键值对的形式不同。
- 不同:使用emplace与insert插入键值对时,如果unordered_map之前已经有这个键,则无法插入,最终这个键对应的值也没有被修改;使用下标插入时,如果之前已经有这个键了,则把该键对应的值修改为新值。
删除元素
使用erase函数删除
参数:
- 键
- 迭代器
- 两个迭代器,删除这两个迭代器范围内的键值对。注: 传入参数为(迭代器1,迭代器2),删除元素的范围是[迭代器1指向元素, ([迭代器2]-1)指向元素]。
unordered_map<string,int> m;
m.emplace("张三",0);
m.emplace("李四",1);
m.emplace("王五",2);
//通过键删除
//m.erase("张三");
//通过迭代器删除
//unordered_map<string,int>::iterator it = m.begin();
//m.erase(it);
//通过迭代器范围删除
unordered_map<string,int>::iterator it1 = m.begin();
it1++;
m.erase(it1,m.end());
showMap(m);
查找元素
- count(): 参数为键,如果找到返回1,反之返回0。
- find():参数为键,如果找到返回对应位置迭代器,反之返回容器末尾迭代器。
unordered_map<string,int>m;
m.insert(make_pair("张三",0));
m.insert(make_pair("李四",1));
m.insert(make_pair("王五",2));
if(m.count("张三")) cout<<"张三"<<endl;
unordered_map<string,int>::iterator it = m.find("李四");
if(it!=m.end()) cout<<"李四: "<<it->second<<endl;
unordered_set
增加元素
和unordered_map类似,主要是通过insert函数和emplace函数实现增加元素
//头文件
#include <iostream>
#include <unordered_set>
using namespace std;
void showSet(unordered_set<string> &s){
unordered_set<string>::iterator it;
for(it=s.begin();it!=s.end();it++){
cout<<*it<<" ";
}
cout<<endl;
}
int main(){
//增加元素 insert emplace
unordered_set<string> s;
s.insert("张三");
s.emplace("李四");
showSet(s);
}
删除元素
删除元素也与unordered_map类似,使用erase函数,并且有三种参数传递模式
- 传值
- 传对应位置的迭代器
- 传入两个迭代器,删除范围内的元素。注: 传入参数为(迭代器1,迭代器2),删除元素的范围是[迭代器1指向元素, ([迭代器2]-1)指向元素]。
//删除元素
//按值删除
//s.erase("张三");
//按迭代器删除
//unordered_set<string>::iterator it = s.begin();
//s.erase(it);
//按迭代器范围删除
unordered_set<string>::iterator it = s.begin();
it++;
s.erase(it,s.end());
showSet(s);
自定义类型的哈希表
因为unordered_set和unordered_map的底层实现都是哈希表,而默认哈希函数是针对基本数据类型的,对于用户自定义的类型(类、结构体),需要重写哈希函数。
需要做的有两步:
- 在类中重载==运算符,使得编译器知道在发生哈希碰撞时如何处理
- 重写hash函数,具体做法为,自定义一个hash结构体,并重载()运算符,返回size_t类型的变量,一般哈希的方式为异或。
最后,在定义unordered_map时,把结构体作为第三个参数传入<>中。
//实现时间类的运算符重载
#include <iostream>
#include <unordered_map>
using namespace std;
class Line{
private:
int len,col;
public:
Line(){}
Line(int _l, int _c):len(_l),col(_c){}
~Line(){
cout << "这是析构函数" << endl;
}
void print() const {
cout << len << " " << col << endl;
}
bool operator==(const Line &l) const{
return len == l.len && col == l.col;
}
int getLen() const{
return len;
}
int getCol() const{
return col;
}
};
struct createhash{
size_t operator()(const Line &l) const{
return hash<int>()(l.getLen()) ^ hash<int>()(l.getCol());
}
};
int main(){
unordered_map<Line,int,createhash> m;
Line *l = new Line(2,3);
l->print();
//delete l;
return 0;
}