本文主要是介绍【C++STL详解(十三)】unordered系列容器的介绍与使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
前言
一、unordered_map
介绍
使用
构造方式
修改
容量
迭代器
元素访问
查询
桶操作
二、unordered_set
介绍
使用
构造
修改
容量
迭代器(只有单向)
查询
桶操作
三、unordered系列的性能测试
前言
前面提到的map/set是C++98提供的关联式容器,底层结构是红黑树,最差情况下需要比较树得高度次,若树的结点十分多时,查询效率也不是很理想。C++11中,又提供了4个unordered系列容器,使用起来和map/set基本类似,只是底层结构不同。unordered系列底层是哈希结构(严格来说是哈希桶结构),最快的查询可以达到O(1)。
一、unordered_map
介绍
- unordered_map是存储<key,value>键值对的关联式容器,KV模型
- 键值key通常用于惟一地标识元素(不存在相同元素),而映射值是一个对象,其内容与此
键关联。键和映射值的类型可能不同。 - 内部没有任何的排序,是无序的,这点和map的最大区别,map有序
- unordered_map通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭
代方面效率较低。 - 同样也支持operator【】访问
- 底层是哈希桶结构
- 迭代器是单向的,因为底层结构
使用
使用上和map可以说是基本类似了!除了迭代器
构造方式
unordered_map<string, int> m;//无参构造unordered_map<string, int> m1(m);//拷贝构造unordered_map<string, int> m2(m1.begin(), m1.end());//迭代器区间构造//初始化列表构造unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };
修改
insert | 向容器中插入键值对 |
erase | 删除键值对 |
clear | 清空元素 |
swap | 交换两个容器内容 |
unordered_map<int, int> m;//无参构造vector<int> a = {3,6,9,4,2,10};for (auto b : a){m.insert({ b,b });}m.erase(3);unordered_map<int, int> m1;m.swap(m1);m.clear();
容量
unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };m3.empty();//判空m3.size();//大小
迭代器
begin() | 返回第一个元素的迭代器 |
end() | 返回最后一个元素的下一个位置的迭代器 |
cbegin() | 返回第一个元素的const迭代器 |
cend() | 返回最后一个元素的下一个位置的const迭代器 |
unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };auto it = m3.begin();while (it!=m3.end()){cout << it->first << ":" << it->second << endl;++it;}
注意:这个系列只提供单向迭代器!!
元素访问
operator【】:返回key对应的value的引用,和map一样!功能强大,既能插入又能修改!
unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };m3["aa"] = 4;
查询
iterator find ( const key_type& k ) | 放回key在哈希桶的位置 |
size_type count ( const key_type& k ) const; | 返回哈希桶中关键码为key的个数 |
注意:Key是唯一的,不允许重复,所以count为0/1!
auto it = m3.find("aa");m3.count("aa");
桶操作
bucket_count() | 返回桶的个数 |
bucket_size(n) | 返回n号桶中有效元素的总个数 |
bucket(key) | 返回元素key所在的桶号 |
二、unordered_set
介绍
- unordered_set是存储key的关联式容器,K模型,底层可以看出<key,key>
- 键值key通常用于惟一地标识元素(不存在相同元素)
- 内部没有任何的排序,是无序的,这点和set的最大区别,set有序
- unordered_set通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭
代方面效率较低。 - 底层是哈希桶结构
- 迭代器是单向的,因为底层结构
使用
构造
和set基本一样,这里直接看实例就好了!
unordered_set<int> s;//无参unordered_set<int> s1(s);//拷贝vector<int> a = { 3,6,9,4,2,10,3 };unordered_set<int> s2(a.begin(),a.end());//迭代区间//初始化列表unordered_set<int> s3 = { 6,7,1,2,4,9,10 };
修改
unordered_set<int> m;//无参构造vector<int> a = {3,6,9,4,2,10};for (auto b : a){m.insert(b);}m.erase(3);unordered_set<int> m1;m.swap(m1);m.clear();
容量
unordered_set<int> s3 = { 3,6,9,4,2,10,3 };s3.size();s3.empty();
迭代器(只有单向)
unordered_set<int> s3 = { 3,6,9,4,2,10,3 };auto it = s3.begin();while (it != s3.end()){cout << *it << endl;++it;}
查询
auto it = s3.find(3);
s3.count(3);// 0/1
桶操作
bucket_count() | 返回桶的个数 |
bucket_size(n) | 返回n号桶中有效元素的总个数 |
bucket(key) | 返回元素key所在的桶号 |
cout << s3.bucket_count() << endl;//统计桶的总数cout << s3.bucket_size(3) << endl;//返回3号桶中的数据个数cout << s3.bucket(3) << endl;//放回3所在的桶号
注意:还有两个容器这里就不过多介绍了,这几个容器使用起来差别不算很大,也比较简单,大家可以点击unordered_multiset和unordered_multimap查看,区别就是multi系列可以存在重复元素
三、unordered系列的性能测试
void test_set2()
{const size_t N = 1000000;unordered_set<int> us;set<int> s;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; ++i){//v.push_back(rand()); // N比较大时,重复值比较多//v.push_back(rand()+i); // 重复值相对少v.push_back(i); // 没有重复,有序}size_t begin1 = clock();for (auto e : v){s.insert(e);}size_t end1 = clock();cout << "set insert:" << end1 - begin1 << endl;size_t begin2 = clock();for (auto e : v){us.insert(e);}size_t end2 = clock();cout << "unordered_set insert:" << end2 - begin2 << endl;int m1 = 0;size_t begin3 = clock();for (auto e : v){auto ret = s.find(e);if (ret != s.end()){++m1;}}size_t end3 = clock();cout << "set find:" << end3 - begin3 << "->" << m1 << endl;int m2 = 0;size_t begin4 = clock();for (auto e : v){auto ret = us.find(e);if (ret != us.end()){++m2;}}size_t end4 = clock();cout << "unorered_set find:" << end4 - begin4 << "->" << m2 << endl;cout << "插入数据个数:" << s.size() << endl;cout << "插入数据个数:" << us.size() << endl << endl;size_t begin5 = clock();for (auto e : v){s.erase(e);}size_t end5 = clock();cout << "set erase:" << end5 - begin5 << endl;size_t begin6 = clock();for (auto e : v){us.erase(e);}size_t end6 = clock();cout << "unordered_set erase:" << end6 - begin6 << endl << endl;}int main()
{test_set2();//test_map1();return 0;
}
大家可以copy到自己的编译器看看其他不同的结果,上述代码的结果如下:
可以看到unordered系列查找的速度确实快啊!因为底层的结构。
如果对你有那么一点帮助,欢迎点赞+收藏哦!
这篇关于【C++STL详解(十三)】unordered系列容器的介绍与使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!