文章目录
在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到以二为底N的对数,即在最差的情况下,需要比较红黑树的高度次,所以在数的节点非常多的时候,查询效率也不理想。最好的查询是,进行很少的比较次数就能将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方法基本类似,只是其底层结构不同,它们四个分别是unordered_map、unordered_set、unordered_multimap和unordered_multiset。map系列是映射,set系列是集合。
unordered_map
- unordered_map是存储<key,value>键值对的关联式容器,其允许通过key快速的索引到与其对应的value。
- 在unordered_map中,键值通常用来唯一的标识元素,而映射值是一个对象,其内容与此键关联,键和映射值的类型可能不同。
- 与以红黑树作为底层结构的map最大的不同是,unordered_map在内部没有对<key,value>按照任何特定的顺序排序,为了能在常数范围内找到key对应的value,unordered_map将相同哈希值的键值放在对应的桶中。
- unordered_map容器通过key访问单个元素比map快,但是它通常在遍历元素子集的范围迭代方面的效率较低。
- unordered_map实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
unordered_map的空构造
int main()
{
unordered_map<int, string> umap;
//构造空的unordered_map
cout << umap.empty() << endl;
//判空
cout << umap.size() << endl;
//求umap中有效元素的个数
return 0;
}
unordered_map的迭代器
int main()
{
//给umap中放入数据
pair<int, string> v[] = {{3,"studying"}, {1,"I"}, {2,"love"}};
int n = sizeof(v) / sizeof(v[0]);
unordered_map<int, string> umap;
for (int i = 0; i < n; ++i)
umap.insert(v[i]);
//利用迭代器对umap的数据进行访问
unordered_map<int, string>::iterator it = umap.begin();
while (it != umap.end())
{
cout << it->first << " : " << it->second << endl;
it++;
}
//unordered_map的元素访问
cout << umap[3] << endl;
return 0;
}
执行结果:
3 : studying
1 : I
2 : love
studying
观察执行结果:不难看出,相较于map结构,我们用unordered_map
定义的umap打印出来的结果是无序
的。
unordered_map的元素访问
nordered_map重载了[],我们可以通过[]对数据进行访问,调用的时候,返回与key对应的value,如果没有对应的key,就返回一个默认值。要注意的是,operator[]函数中实际调用的是插入操作,用参数key和V()构造一个默认值往底层的哈希桶中插入,如果key不在哈希桶中,插入成功,返回V(),插入失败,说明key已经在哈希桶中,将key对应的value返回。
我们不仅可以通过[]来访问元素,也可以通过它来往unordered_map中插入数据,代码如下:
int main()
{
//给umap中放入数据
pair<int, string> v[] = {{3,"studying"}, {1,"I"}, {2,"love"}};
int n = sizeof(v) / sizeof(v[0]);
unordered_map<int, string> umap;
for (int i = 0; i < n; ++i)
umap.insert(v[i]);
//利用迭代器对umap的数据进行访问
unordered_map<int, string>::iterator it = umap.begin();
while (it != umap.end())
{
cout << it->first << " : " << it->second << endl;
it++;
}
cout << "size=" << umap.size() << endl;
umap[4] = "China";//利用[]放入数据
umap[9] = "C++";
it = umap.begin();
while (it != umap.end())
{
cout << it->first << " : " << it->second << endl;
it++;
}
cout << "size=" << umap.size() << endl;
return 0;
}
unordered_map的查询
int main()
{
//给umap中放入数据
pair<int, string> v[] = { {3,"studying"}, {1,"I"}, {2,"love"} };
int n = sizeof(v) / sizeof(v[0]);
unordered_map<int, string> umap;
for (int i = 0; i < n; ++i)
umap.insert(v[i]);
auto p = umap.find(3);//查找函数,返回指向key结点的指针
cout << p->first << " : " << p->second << endl;
size_t cou = umap.count(2);
cout << cou << endl;
cou = umap.count(9);
cout << cou << endl;
}
执行结果:
3 : studying
1
0
unordered_map的修改操作
int main()
{
pair<int, string> v[] = { {3,"studying"}, {1,"I"}, {2,"love"} };
int n = sizeof(v) / sizeof(v[0]);
unordered_map<int, string> umap;
umap.insert(v, v + n);//插入键值对,按区间插入
umap.erase(3);//删除容器中的键值对
umap.clear();//清空容器中所有的有效元素
return 0;
}
unordered_map的桶操作
函数声明 | 功能介绍 |
---|---|
size_t bucket_count()const | 返回哈希桶中桶的总个数 |
size_t bucket_size(size_t n)const | 返回n号桶中有效元素的个数 |
size_t bucket(const K& key) | 返回元素key所在的桶号 |
int main()
{
pair<int, string> v[] = { {3,"studying"}, {1,"I"}, {2,"love"} };
int n = sizeof(v) / sizeof(v[0]);
unordered_map<int, string> umap;
umap.insert(v, v + n);
cout << "bucket count = " << umap.bucket_count() << endl;
for (int i = 0; i < umap.bucket_count(); ++i)
{
cout << i << " : " << umap.bucket_size(i) << endl;
}
int key[] = { 1,2,3 };
for (int i = 0; i < n; ++i)
{
cout << key[i] << " : " << umap.bucket(key[i]) << endl;
}
return 0;
}
unordered_multimap
相对于unordered_map而言,unorderd_multimap的不同之处在于它允许重复
元素的存在。
int main()
{
pair<int, string> v[] = { {3,"studying"}, {1,"I"}, {2,"love"} ,{3,"learning"} };
int n = sizeof(v) / sizeof(v[0]);
unordered_multimap<int, string> ummap;
ummap.insert(v, v + n);
for (const auto &e : ummap)
{
cout << e.first << " : " << e.second << endl;
}
return 0;
}
map和unordered_map的使用场景
如果我们要用到映射,map和unordered_map要怎样选择呢?我们知道这两者的不同就在于其底层实现结构的不同,前者底层结构是红黑树,后者底层结构是哈希表,对红黑树来说,其中序遍历是有序的,所以map的优势在于其底层结构的有序,所以如果我们对数据的顺序有要求的话,就采用map,其他的情况尽量采用unordered_map,因为它的底层结构是哈希表,数据的查询效率更高。另外就是如果对数据迭代访问的需求比较多的话,尽量采用map,如果查找的需求更多,访问的需求较少,那unordered_map就更加有优势。总的来说,排序和数据访问方面,map更有优势;数据查询方面,unordered_map更有优势
,在实际应用中,它俩的选择可以根据实际需求来决定。
unordered_set
- unordered_set是以不按特定顺序存储唯一元素的容器,并允许根据其值快速检索单个元素。
- 在unordered_set中,元素的值同时也是其键,唯一标识它,键是不可变的,因此unordered_set中的元素不能在容器中修改,但是可以插入和删除。
- 在内部,unordered_set不按任何特定顺序进行排序,而是根据其哈希值组织到桶中,以允许直接按其值快速访问单个元素。
- unordered_set比有序的set更块的通过其键访问单个元素,但是在遍历元素子集的范围迭代方面效率较低。
int main()
{
int ar[] = { 1,5,8,3,9,6,45,43,76,9,2,87 };
int n = sizeof(ar) / sizeof(ar[0]);
unordered_set<int> uset;
uset.insert(ar, ar + n);
for (const auto &e : uset)
cout << e << " ";
cout << endl;
return 0;
}
执行结果:
9 1 45 5 8 43 3 6 76 2 87
unordered_set的用法和unordered_map非常接近,后面的用法可以参考unordere_set。
unordered_multiset
相对于unordered_set而言,unorderd_multiset的不同之处在于它允许重复
元素的存在。
int main()
{
int ar[] = { 1,5,8,3,9,6,45,43,76,9,2,87,87,87,87,87,87 };
int n = sizeof(ar) / sizeof(ar[0]);
unordered_multiset<int> uset;
uset.insert(ar, ar + n);
for (const auto &e : uset)
cout << e << " ";
cout << endl;
return 0;
}
执行结果:
9 9 1 45 5 8 43 3 6 76 2 87 87 87 87 87 87