赞
踩
⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:C++进阶
⭐代码仓库:C++进阶
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!
在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2 N log2N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同。
其定义方式如下:
void test_unordered_map1() { // 构造一个空的key为int,value为double的unordered_map unordered_map<int, double> um1; // 给um1赋上值 um1.insert(make_pair(1, 1.1)); um1.insert(make_pair(2, 2.2)); um1.insert(make_pair(3, 3.3)); um1.insert(make_pair(4, 4.4)); // 拷贝构造 unordered_map<int, double> um2(um1); // 迭代器区间拷贝um2的一段 unordered_map<int, double> um3(um2.begin(), um2.end()); // for循环打印一下um3,um3没问题则um1和um2都没问题 for (auto& e : um3) { cout << e.first<< "=>" << e.second << " "; } cout << endl; }
成员函数 | 功能 |
---|---|
insert | 插入键值对 |
erase | 删除指定key的值的键值对 |
size | 获取容器中元素的个数 |
find | 查找指定key值的键值对 |
empty | 判断容器是否为空 |
clear | 清空当前容器 |
swap | 交换两个容器中的数据 |
count | 获取容器中指定key值的元素的个数 |
[] | 运算符重载的[]功能很强大,有插,改、找等功能 |
begin() | 获取容器中第一个元素的正向迭代器 |
end() | 获取容器中最后一个元素的下一个元素的正向迭代器的 |
重点讲一下[]:
1、若当前容器中已经存在着键值为key的键值对,则返回该键值对value的引用。
2、若当前容器中没有键值为key的键值对,则先插入键值对<key, value()>,然后再返回该键值对中value的引用。
下面直接看代码,关于上述所有的代码操作:
void test_unordered_map2() { // 构造一个空的key为int,value为string的unordered_map unordered_map<int, string> um1; // 插入方法一:构造匿名对象插入 um1.insert(pair<int, string>(1, "111")); um1.insert(pair<int, string>(2, "222")); um1.insert(pair<int, string>(3, "333")); // 插入方法二:调用make_pair插入 um1.insert(make_pair(4, "444")); um1.insert(make_pair(5, "555")); um1.insert(make_pair(6, "666")); // 插入方法三:用operator[] um1[7] = "777"; um1[8] = "888"; um1[9] = "999"; um1[10] = "000"; // 遍历方式一:利用迭代器进行遍历打印 //unordered_map<int, string>::iterator it = um1.begin(); auto it = um1.begin(); while (it != um1.end()) { cout << (*it).first << "=>" << (*it).second << " "; ++it; } cout << endl; // 1=>111 2=>222 3=>333 4=>444 5=>555 6=>666 7=>777 8=>888 9=>999 10=>000 // 遍历方法二:利用for循环进行遍历打印 for (auto& e : um1) { cout << e.first<< "=>" << e.second << " "; } cout << endl; // 1=>111 2=>222 3=>333 4=>444 5=>555 6=>666 7=>777 8=>888 9=>999 10=>000 // 删除操作1:根据键值对key删除 um1.erase(5); // 删除操作2:根据迭代器进行删除 unordered_map<int, string>::iterator rit = um1.find(7); // 顺带使用键值对key就可以用find函数了 if (rit != um1.end()) { um1.erase(rit); } // 遍历打印一下,用for循环方便快捷一点 for (auto& e : um1) { cout << e.first << "=>" << e.second << " "; } cout << endl; // 1=>111 2=>222 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000 // 修改键值对:通过find获得迭代器进行修改 auto pos = um1.find(1); if (pos != um1.end()) { pos->second = "11/11"; } // 修改键值对:通过operator[]运算符重载进行修改 um1[2] = "22/22"; // 打印一下 for (auto& e : um1) { cout << e.first << "=>" << e.second << " "; } cout << endl; // 1=>11/11 2=>22/22 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000 // 判空 cout << um1.empty() << endl; // 0 -- 不空 // 计算容器的大小 cout << um1.size() << endl; // 8个 // 计算容器中键值对的大小 cout << um1.count(3) << endl; // 1 // 交换两容器中的数据 unordered_map<int, string> tmp{{11, "123"}, { 22, "345" }}; um1.swap(tmp); for (auto& e : tmp) { cout << "tmp=>" << " "; cout << e.first << "=>" << e.second << " "; } cout << endl; // tmp=> 1=>11/11 2=>22/22 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000 for (auto& e : um1) { cout << "um1=>" << " "; cout << e.first << "=>" << e.second << " "; } cout << endl; // um1=> 11=>123 22=>345 // 清空 um1.clear(); for (auto& e : um1) { cout << e.first << "=>" << e.second << " "; } cout << endl; }
这个容器与unordered_map基本一致,这两个的区别在于multimap允许键值对的冗余,也就是可以允许key和value有不同的值。
void test_unordered_map3()
{
unordered_multimap<int, string> ummp1;
ummp1.insert(make_pair(2023, "yes"));
ummp1.insert(make_pair(2023, "no"));
ummp1.insert(make_pair(2023, "before"));
ummp1.insert(make_pair(2023, "now"));
for (auto& e : ummp1)
{
cout << e.first << "=>" << e.second << " ";
}
cout << endl;
}
还有三个不同:
1、unordered_map和unordered_multimap的find函数:
find函数 | 功能 |
---|---|
unordered_map | 返回键值为key的键值对的迭代器 |
unordered_multimap | 返回底层哈希表中第一个找到的键值为key的键值对的迭代器 |
2、count函数功能
count函数 | 功能 |
---|---|
unordered_map | 键值为key的键值对存在则返回1,不存在则返回0(find成员函数可替代) |
unordered_multimap | 返回键值为key的键值对的个数(find成员函数不可替代) |
3、operator[]函数功能
我们在unordered_multimap中是没有这个operator[]重载的,因为这个容器中是可以冗余的,所以我们不确定找的是哪一个,会导致很多的错误,所以我们的unordered_multimap是没有operator[]这个的!
1、unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素。
2、在unordered_set中,元素的值同时也是唯一地标识它的key。
3、在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。
4、unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低。
5、它的迭代器至少是前向迭代器。
void test_unordered_set1() { // 构造一个空壳的us1的unordered_set的容器 unordered_set<int> us1; // 插入几个值 us1.insert(1); us1.insert(2); us1.insert(3); us1.insert(4); // 拷贝构造 unordered_set<int> us2(us1); // 迭代器区间构造 unordered_set<int> us3(us2.begin(), us2.end()); // for循环打印一下 for (auto& e : us3) { cout << e << " "; } cout << endl; }
成员函数 | 功能 |
---|---|
insert | 插入指定元素 |
erase | 删除指定元素 |
size | 获取容器中元素的个数 |
find | 查找指定元素 |
empty | 判断容器是否为空 |
clear | 清空当前容器 |
swap | 交换两个容器中的数据 |
count | 获取容器中指定元素的个数 |
[] | 运算符重载的[]功能很强大,有插,改、找等功能 |
begin() | 获取容器中第一个元素的正向迭代器 |
end() | 获取容器中最后一个元素的下一个元素的正向迭代器的 |
void test_unordered_set2() { // 先构造一个空的容器 unordered_set<int> us1; // 插入元素(只有这一种插入法) us1.insert(1); us1.insert(2); us1.insert(3); us1.insert(1); us1.insert(4); us1.insert(5); // 遍历容器第一种方法:迭代器遍历 unordered_set<int>::iterator it = us1.begin(); while (it != us1.end()) { cout << *it << " "; ++it; } cout << endl; // 1 2 3 4 5 // 遍历容器第二种方法:for循环 for (auto& e : us1) { cout << e << " "; } cout << endl; // 1 2 3 4 5 // 删除元素的方式一:直接找到值进行删除 us1.erase(1); // 删除元素的方法二:利用迭代器进行删除 unordered_set<int>::iterator pos = us1.find(2); if (pos != us1.end()) { us1.erase(pos); } // 打印一下 for (auto& e : us1) { cout << e << " "; } cout << endl; // 3 4 5 // 判断容器是否为空 cout << us1.empty() << endl; // 0 // 获取值为3的个数 cout << us1.count(3) << endl; // 1 // 查看当前容器的容量 cout << us1.size() << endl; // 3 // 交换数据 unordered_set<int> tmp{99, 88, 77, 66}; us1.swap(tmp); // 打印一下 for (auto& e : us1) { cout << e << " "; } cout << endl; // 99 88 77 66 // 打印一下 for (auto& e : tmp) { cout << e << " "; } cout << endl; // 3 4 5 // 清空 us1.clear(); // 打印一下 for (auto& e : us1) { cout << e << " "; } cout << endl; // }
大致实现的功能与unordered_map相同,但唯一不同的一点是在于这个多功能的set是允许值进行重复的!
void test_unordered_set3() { unordered_multiset<int> ums1; ums1.insert(1); ums1.insert(2); ums1.insert(4); ums1.insert(3); ums1.insert(1); ums1.insert(5); ums1.insert(2); ums1.insert(7); for (auto& e : ums1) { cout << e << " "; } cout << endl; // 1 1 2 2 3 4 5 7 }
这个多功能的set是相较于普通set来讲的count函数是返回的个数,而普通set的count函数是如果存在则返回1,不存在则返回0。
这个多功能set相较于普通set来讲的find函数是返回底层哈希表中第一个找到的键值为val的元素的迭代器,而普通set则是返回简单的key。
性能测试来一波:
#include <iostream> #include <set> #include <unordered_set> #include <time.h> using namespace std; int main() { int N = 1000; vector<int> v; v.reserve(N); srand((unsigned int)time(NULL)); //随机生成N个数字 for (int i = 0; i < N; i++) { v.push_back(rand()); } //将这N个数插入set容器 set<int> s; clock_t begin1 = clock(); for (auto e : v) { s.insert(e); } clock_t end1 = clock(); //将这N个数插入unordered_set容器 unordered_set<int> us; clock_t begin2 = clock(); for (auto e : v) { us.insert(e); } clock_t end2 = clock(); //分别输出插入set容器和unordered_set容器所用的时间 cout << "set insert: " << end1 - begin1 << endl; cout << "unordered_set insert: " << end2 - begin2 << endl; //在set容器中查找这N个数 clock_t begin3 = clock(); for (auto e : v) { s.find(e); } clock_t end3 = clock(); //在unordered_set容器中查找这N个数 clock_t begin4 = clock(); for (auto e : v) { us.find(e); } clock_t end4 = clock(); //分别输出在set容器和unordered_set容器中查找这N个数所用的时间 cout << "set find: " << end3 - begin3 << endl; cout << "unordered_set find: " << end4 - begin4 << endl; //将这N个数从set容器中删除 clock_t begin5 = clock(); for (auto e : v) { s.erase(e); } clock_t end5 = clock(); //将这N个数从unordered_set容器中删除 clock_t begin6 = clock(); for (auto e : v) { us.erase(e); } clock_t end6 = clock(); //分别输出将这N个数从set容器和unordered_set容器中删除所用的时间 cout << "set erase: " << end5 - begin5 << endl; cout << "unordered_set erase: " << end6 - begin6 << endl; return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。