零、前言
本章主要讲解unordered系列关联式容器及其底层结构和模拟实现,还有哈希的相关应用等
一、unordered系列关联式容器
- 在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想
- 最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同
- unordered_map/unordered_set与map/set基本上只有底层实现上的区别,前者是哈希,后者是红黑树
- unordered_map/unordered_set与unordered_multimap/unordered_multiset的区别是是否允许键值冗余
- unordered系列关联式容器因为底层不是红黑树了,所以遍历的结果不是排序好的序列
1、unordered_map介绍及使用
- unordered_map是存储<key, value>键值对的关联式容器,其允许通过key值快速的索引到与其对应是value
- 在unordered_map中,键值通常用于唯一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同
- 在内部,unordered_map没有对<key, value>按照任何特定的顺序排序,为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中
- unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低
- unordered_map实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value
- 它的迭代器是单向正向迭代器
- unordered_map的构造
函数声明 |
功能介绍 |
unordered_map |
构造不同格式的unordered_map对象 |
- unordered_map的容量
函数声明 |
功能介绍 |
bool empty() const |
检测unordered_map是否为空 |
size_t size() const |
获取unordered_map的有效元素个数 |
- unordered_map的迭代器
函数声明 |
功能介绍 |
begin |
返回unordered_map第一个元素的迭代器 |
end |
返回unordered_map最后一个元素下一个位置的迭代器 |
cbegin |
返回unordered_map第一个元素的const迭代器 |
cend |
返回unordered_map最后一个元素下一个位置的const迭代器 |
- unordered_map的元素访问
函数声明 |
功能介绍 |
operator[] |
返回与key对应的value,没有一个默认值 |
注意:该函数中实际调用哈希桶的插入操作,用参数key与V()构造一个默认值往底层哈希桶中插入,如果key不在哈希桶中,插入成功,返回V(),插入失败,说明key已经在哈希桶中,将key对应的value返回
- unordered_map的查询
函数声明 |
功能介绍 |
iterator find(const K& key) |
返回key在哈希桶中的位置 |
size_t count(const K& key) |
返回哈希桶中关键码为key的键值对的个数 |
注意:unordered_map中key是不能重复的,因此count函数的返回值最大为 1,对于unordered_multimap才是允许键值冗余的
- unordered_map的修改操作
函数声明 |
功能介绍 |
insert |
向容器中插入键值对 |
erase |
删除容器中的键值对 |
void clear() |
清空容器中有效元素个数 |
void swap(unordered_map&) |
交换两个容器中的元素 |
- unordered_map的桶操作
函数声明 |
功能介绍 |
size_t bucket_count()const |
返回哈希桶中桶的总个数 |
size_t bucket_size(size_t n)const |
返回n号桶中有效元素的总个数 |
size_t bucket(const K& key) |
返回元素key所在的桶号 |
void test_unordered_map()
{
unordered_map<string, string> dict;
dict.insert(make_pair("string", ""));
dict.insert(make_pair("sort", ""));
auto it = dict.begin();
while (it != dict.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}
2、unordered_set的介绍及使用
- unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素
- 在unordered_set中,元素的值同时也是唯一地标识它的key
- 在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中
- unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低
- 它的迭代器是单向前向迭代器
- unordered_set当中常用的成员函数
成员函数 |
功能 |
insert |
插入指定元素 |
erase |
删除指定元素 |
find |
查找指定元素 |
size |
获取容器中元素的个数 |
empty |
判断容器是否为空 |
clear |
清空容器 |
swap |
交换两个容器中的数据 |
count |
获取容器中指定元素值的元素个数 |
- 迭代器相关函数
成员函数 |
功能 |
begin |
获取容器中第一个元素的正向迭代器 |
end |
获取容器中最后一个元素下一个位置的正向迭代器 |
void test_unordered_set()
{
unordered_set<int> s;
s.insert(3);
s.insert(4);
s.insert(5);
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(6);
unordered_set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
3、性能比较
void test_op()
{
set<int> s;
unordered_set<int> us;
const int n = 1000000;
vector<int> v;
srand(time(0));
for (size_t i = 0; i < n; ++i)
{
v.push_back(rand());
}
size_t begin1 = clock();
for (auto e : v)
{
s.insert(e);
}
size_t end1 = clock();
size_t begin2 = clock();
for (auto e : v)
{
us.insert(e);
}
size_t end2 = clock();
cout << "set insert:" << end1 - begin1 << endl;
cout << "unordered_set insert:" << end2 - begin2 << endl;
cout << "=====================" << endl;
size_t begin3 = clock();
for (auto e : v)
{
s.find(e);
}
size_t end3 = clock();
size_t begin4 = clock();
for (auto e : v)
{
us.find(e);
}
size_t end4 = clock();
cout << "set find:" << end3 - begin3 << endl;
cout << "unordered_set find:" << end4 - begin4 << endl;
cout << "=====================" << endl;
size_t begin5 = clock();
for (auto e : v)
{
s.erase(e);
}
size_t end5 = clock();
size_t begin6 = clock();
for (auto e : v)
{
us.erase(e);
}
size_t end6 = clock();
cout << "set erase:" << end5 - begin5 << endl;
cout << "unordered_set erase:" << end6 - begin6 << endl;
}
总结:使用底层为哈希的容器总体的效率是非常高的,对于关联式set/map的复杂度能达到O(logN),而unordered系列关联式容器可以达到接近O(1)的水平
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
评论(0)