• 【C++】undered_set与undered_map


    引言:前面我们知道了STL库的容器中的序列式容器包括(vector.list,deque)。还要关联式容器(map,set)。 

    容器分为三大类:序列式容器关联式容器,容器适配器(不讲了

     顺序性容器与关联性容器:

    • 顺序性容器 是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集顺序性容器中的每个元素均有固定的位置,除非用删除或插入的操作改变这个位置。这个位置和元素本身无关,而和操作的时间和地点有关,顺序性容器不会根据元素的特点排序而是直接保存了元素操作时的逻辑顺序。比如我们一次性对一个顺序性容器追加三个元素,这三个元素在容器中的相对位置和追加时的逻辑次序是一致的。
    • 关联式容器 和顺序性容器不一样,关联式容器是非线性的树结构,更准确的说是二叉树结构。各元素之间没有严格的物理上的顺序关系,也就是说元素在容器中并没有保存元素置入容器时的逻辑顺序。但是关联式容器提供了另一种根据元素特点排序的功能,这样迭代器就能根据元素的特点“顺序地”获取元素。

    关联性容器的有无序:

    • 有序容器的底层是红黑树实现的,而红黑树是一种不太严格的AVL平衡搜索二叉树,所以像map,set中存放的数据都是有序排列的。访问速度较慢
    • 无序容器的底层是哈希表实现的。哈希表通过把关键码值映射到表中一个位置来访问记录。其存储的内容是无序的。但是访问速度较快。

    map与unordered的优缺点:

    map:

    1. 优点:有序性,这是map结构最大的优点,内部实现一个红黑树使得map的很多操作在lgn的时间复杂度下就可以实现,因此效率非常的高。
    2. 缺点: 空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的

    unordered_map:

    1. 优点: 因为内部实现了哈希表,因此其查找速度非常的快
    2. 缺点: 哈希表的建立比较耗费时间

    2.undered_set和set的效率

    老说哈希表比红黑树的底层快,到底有多快,上手比较一下就知道了。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. void test_unordered_set()
    8. {
    9. vector<int> v;
    10. v.reserve(10000);
    11. srand((unsigned int)time(NULL));
    12. for (int i = 0; i < 10000; i++)
    13. {
    14. v.push_back(rand());
    15. }
    16. //插入
    17. set<int> s;
    18. size_t begin1 = clock();
    19. for (auto e : v)
    20. {
    21. s.insert(e);
    22. }
    23. size_t end1 = clock();
    24. unordered_set<int> us;
    25. size_t begin2 = clock();
    26. for (auto e : v)
    27. {
    28. us.insert(e);
    29. }
    30. size_t end2 = clock();
    31. cout << "set insert time:" << end1 - begin1 << endl;
    32. cout << "unorder_set insert time:" << end2 - begin2 << endl;
    33. //查找
    34. size_t begin3 = clock();
    35. for (auto e : v)
    36. {
    37. s.find(e);//set自带的查找效率是O(logn)
    38. }
    39. size_t end3 = clock();
    40. size_t begin4 = clock();
    41. for (auto e : v)
    42. {
    43. us.find(e); //unordered_set自带的查找,优点:使用哈希特性查找,效率高--O(1)
    44. }
    45. size_t end4 = clock();
    46. cout << "set find time:" << end3 - begin3 << endl;
    47. cout << "unorder_set find time:" << end4 - begin4 << endl;
    48. //删除
    49. size_t begin5 = clock();
    50. for (auto e : v)
    51. {
    52. s.erase(e);
    53. }
    54. size_t end5 = clock();
    55. size_t begin6 = clock();
    56. for (auto e : v)
    57. {
    58. us.erase(e);
    59. }
    60. size_t end6 = clock();
    61. cout << "set erase time:" << end5 - begin5 << endl;
    62. cout << "unorder_set erase time:" << end6 - begin6 << endl;
    63. }
    64. int main()
    65. {
    66. test_unordered_set();
    67. return 0;
    68. }

    先来10000个数的比较。

    再来100000比较一下: 到底快不快,各位细品,我就不说话了。

    3.undered_set 

    3.1特点

    • (1) unordered_map是存储键值对的关联式容器,对value进行快速索引。
    • (2)在unordered_set中,元素的值同时是其键,是唯一标识,键和映射值的类型相同,键不可修改。unordered_set中的元素在容器不可修改,但是可以插入和删除元素。
    • (3)在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。
    • (4)unordered_set比set通过键访问单个元素的速度更快,但它通常在遍历元素子集的范围迭代方面效率较低。
    • (5)容器中的迭代器至少有正向迭代器。

    3.2三种构造方式 

    • 1、构造一个空容器
    unordered_set<int> us1;
    • 2、拷贝构造一个容器
    unordered_set<int> us2(us1)
    • 3、使用迭代器构造一段区间
    1. string str("Hash")
    2. unordered_set us3(str.begin(), str.end());

    3.3函数接口

    成员函数 功能说明                  

    功能说明
    begin    获取容器中第一个元素的正向迭代器
    end获取容器中最后一个元素下一个位置的正向迭代器
    insert插入指定数据
    erase删除指定元素
    find查找指定元素
    size获取容器中元素的个数
    clear 清空容器
    swap交换两个容器中的数据
    count获取容器中指定元素值的元素个数

    1. void test_unordered1()
    2. {
    3. unordered_set<int> us1;
    4. us1.insert(1);
    5. us1.insert(2);
    6. us1.insert(-1);
    7. us1.insert(3);
    8. us1.insert(4);
    9. us1.insert(5);
    10. for (auto e : us1)
    11. {
    12. cout << e << " ";
    13. cout << endl;
    14. }
    15. //判空
    16. cout << "容器容量:"<empty() << endl; //不为空 0
    17. //判断容器当前数据个数
    18. cout << "容器当前数据个数:"<size() << endl; //5
    19. //求容器当前可存储的最多数据个数
    20. cout << us1.max_size() << endl;
    21. //迭代器+查找
    22. unordered_set<int>::iterator it = us1.find(-1);
    23. if (it != us1.end())
    24. {
    25. cout << "找到了:" << *it << endl;
    26. //删除
    27. us1.erase(it);
    28. }
    29. for (auto e : us1)
    30. {
    31. cout << e << " ";
    32. cout << endl;
    33. }
    34. //插入区间段
    35. unordered_set<int> us2(us1.begin(),us1.end());
    36. unordered_set<int>::iterator itr = us2.begin();
    37. while (itr != us2.end())
    38. {
    39. cout << *itr << endl;
    40. itr++;
    41. }
    42. /*for (auto e : us2)
    43. {
    44. cout << e << endl;
    45. }*/
    46. }

    xdm,打印的结果是无序的,可不像set一样是有序的。 

    3.4延伸(unorder_multiset )

    unorder_nultiset和unorder_set其实没啥大的区别,就是它允许简直冗余,如果插入两个相同的数,它会正确打印,但是 unorder_set不行。

    find函数的功能略微有点差异:

    unordered_set对象返回值为key的元素的迭代器位置
    unordered_multiset对象返回底层哈希表中的第一个值为key的元素的迭代器

    4. unordered_map

    4.1特点

    map知道不?对,这个跟他有关系但是关系不多。这个也是无序的。

    • 1、unordered_map是存储键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
    • 2、在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
    • 3、在内部,unordered_map没有对按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
    • 4、unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
    • 5、unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
    • 6、它的迭代器至少是前向迭代器。

     4.2函数构造

    map咋构造它咋构造。

    • 1、构造一个空容器:
    unordered_mapint> mp1;
    • 2、拷贝构造一个容器:
    unordered_mapint> mp2(mp1);
    • 3、使用迭代器区间构造一个容器:
    unordered_mapint> mp2(mp1.begin(), mp1.end());

    4.3相关函数接口 

    功能我就不在一一讲解了,兄弟们自行到官网去查吧,直接上代码。

    头文件#include

    1. void test_unordered_map()
    2. {
    3. unordered_map<int, string> mp1;
    4. pair<int, string> kv(1111, "男神节");
    5. //5种插入方法
    6. mp1.insert(kv);
    7. mp1.insert(pair<int, string>(1506, "time"));
    8. mp1.insert(make_pair(2022, "year"));
    9. mp1[2222] = "csdn"; //map就有用[]访问
    10. mp1.insert({ 1509,"节日快乐!" });
    11. for (auto e : mp1)
    12. {
    13. cout << e.first << " ";
    14. cout << endl;
    15. }
    16. unordered_map<int, string>::iterator it = mp1.begin();
    17. while (it != mp1.end())
    18. {
    19. cout << it->first << ":" << it->second << " ";
    20. it++;
    21. }
    22. cout << endl; //1111:男神节 1506:time 2022:year 2222:csdn 1509:节日快乐!
    23. //2:范围for
    24. for (auto e : mp1)
    25. {
    26. cout << e.first << ":" << e.second << " ";
    27. }
    28. cout << endl; //1111:男神节 1506 : time 2022 : year 2222 : csdn 1509 : 节日快乐!
    29. }

                                                            祝兄弟们节日快乐!

    1. void test_unordered_map2()
    2. {
    3. unordered_map<int, string> mp1;
    4. pair<int, string> kv(1111, "男神节");
    5. mp1.insert(kv);
    6. mp1.insert(pair<int, string>(1506, "time"));
    7. mp1.insert(make_pair(2022, "year"));
    8. mp1[2222] = "csdn"; //map就有用[]访问
    9. mp1.insert({ 1509,"节日快乐!" });
    10. //1:根据key删除
    11. mp1.erase(4);
    12. //2:根据迭代器位置删除
    13. unordered_map<int, string>::iterator pos = mp1.find(2222);
    14. if (pos != mp1.end())
    15. {
    16. mp1.erase(pos);
    17. }
    18. for (auto e : mp1)
    19. {
    20. cout << e.first << ":" << e.second << " ";
    21. cout << endl;
    22. }
    23. cout << endl;//1:one 3:three 5:five
    24. /*修改*/
    25. //1:通过迭代器位置修改
    26. pos = mp1.find(1111);
    27. if (pos != mp1.end())
    28. {
    29. pos->second = "1212";
    30. }
    31. //2:通过[]修改
    32. mp1[1533] = "5555";
    33. for (auto e : mp1)
    34. {
    35. cout << e.first << ":" << e.second << " ";
    36. cout << endl;
    37. }
    38. cout << endl;//1:one 3:Ⅲ 5:Ⅴ
    39. }

    4.4延伸(unordered_multimap)

    unordered_multimap跟unordered_map的区别也不是很大,前者能存储重复的数据,后者不行,在一些函数接口上会有一些不同,这个参考前的multimapjike。

  • 相关阅读:
    2023年全球市场氮化铝外延片总体规模、主要生产商、主要地区、产品和应用细分研究报告
    GET 和 POST请求的本质区别是什么?
    为什么电容两端电压不能突变
    四化智造MES(WEB)与金蝶云星空对接集成原材料/标准件采购查询(待采购)连通采购订单新增(原材料采购-采购订单(变更)-TEST)
    druid在springboot中如何整合配置!
    python文件内对应列相乘在求和
    分类常用的神经网络模型,深度神经网络主要模型
    含文档+PPT+源码等]精品基于Uniapp+SSM实现的酒品移动电商平台app[包运行成功]Android毕业设计Java项目源码论文
    Docker Compose介绍和安装
    外卖跑腿系统的关键功能和技术要点
  • 原文地址:https://blog.csdn.net/bit_jie/article/details/127798234