• Day15: C++之STL容器(3/3)


    一、集合set

    头文件<set>

    1.特性:

            ①数据自带排序②没有重复(数据的唯一性)

    2.基本操作:

            ①创建(第一个参数是存储数据的类型,第二个是排序准则)

    1. set<int> setData; //默认方式 从小到大
    2. set<int, less<int>> setData2; //和默认方式一样
    3. set<int, greater<int>> setData3; //从大到小

            ②插入:insert(data)

    setData.insert(temp);

            ③迭代器遍历

    1. for (set<int>::iterator iter = setData.begin(); iter != setData.end(); iter++)
    2. {
    3. cout << *iter << " ";
    4. }

    3.对于自定义类型数据的处理:

            核心问题:重载 第一行的less<····>是作为第二个的默认参数(下为set原型)

     而less即为从小到大  所以我们需要重载<号 (其余同理) (注:一定要是常属性参数+常函数)

    1. class wbm
    2. {
    3. public:
    4. wbm(string name,int age):name(name),age(age){}
    5. bool operator<(const wbm &temp)const
    6. {
    7. return name < temp.name;
    8. }
    9. void print()
    10. {
    11. cout << name << "\t" << age << endl;
    12. }
    13. protected:
    14. string name;
    15. int age;
    16. };
    17. void test_wbm_set()
    18. {
    19. wbm w1("wbm1", 11);
    20. wbm w2("wbm2", 22);
    21. wbm w5("wbm5", 55);
    22. wbm w4("wbm4", 44);
    23. wbm w3("wbm3", 33);
    24. wbm temptest("wbm3", 99);
    25. set<wbm> wbmset = { w1,w2,w3,w4,w5,temptest };
    26. for (auto v : wbmset)
    27. {
    28. v.print();
    29. }
    30. }

    输出结果:(很显然,temptest没有被插入进去)->查重标准是按照重载写的<准则(按照name进行比较的。

     二、多重集合multiset

    1.特性:

            只具有排序功能,不具有去重功能

    2.写法同set

            (不同点在于,multiset仅排序)

    1. void testmultiset()
    2. {
    3. multiset<int> mulData;
    4. for (int i = 0; i < 10; i++)
    5. {
    6. mulData.insert(rand() % 10);
    7. //rand()%26+'A';
    8. //rand()%26+'a';
    9. }
    10. for (auto v : mulData)
    11. {
    12. cout << v << " ";
    13. }
    14. cout << endl;
    15. }

    输出结果:0 1 2 4 4 4 7 8 8 9 

    三、二进制集合bitset

    头文件                        #include<bitset>

    1.特性:(常用于二进制操作)

            管理二进制的容器,不需要传类型(只需要传一个长度->代表有多少个二进制位)

    2.常见功能

            (详见F1微软在线文档,在网安和底层开发会很有用。)

    3.简单实例: 

            ①两种构造方式:

                          以字符串的形式就是直接原封不动的去掉引号,变成二进制

                          以传入一个整数的形式,就是将该整数(十进制)转化为二进制再保存到容器中。

            ②flip():1和0的反转(~)   all():检测每一个位是否都是1         any():检测是否有位含1 

    1. void testmultiset()
    2. {
    3. //多个二进制位
    4. bitset<8> bData("11110000");
    5. cout << bData << endl;
    6. bData.flip(); //等效于~
    7. cout << bData << endl;
    8. cout << bData.all() << endl;
    9. cout << bData.any() << endl;
    10. cout << bData.size() << endl;
    11. cout << bData.none() << endl;
    12. bitset<8> num(7); //将7转化为二进制的形式保存在bitset的容器中。
    13. cout << num << endl;
    14. }

     输出:

    11110000
    00001111
    0
    1
    8
    0
    00000111

     四、映射map

    1.map中存放pair数据类型

                    ->称为数对类型(将两个数据绑定到一起)

                     实际上就是一个两个待实例化的模板结构体

                    访问方式:m_pair.first    m_pair.second 分别访问第一二个绑定的元素

    1. template <class _Ty1, class _Ty2>
    2. struct MyPair
    3. {
    4. _Ty1 first;
    5. _Ty2 second;
    6. MyPair(_Ty1 first, _Ty2 second) :first(first), second(second) {}
    7. };
    8. //map存储的数据是一个数对类型
    9. void testPair()
    10. {
    11. pair<int, string> pData(1, "string");
    12. MyPair<int, string> myPData(1, "string");
    13. cout << pData.first << " " << pData.second << endl;
    14. }

    2.map的特性

            ①自带排序,默认是从小到大

            ②数据唯一性

    3.基本操作

            ①插入:

                    方式一:insert一个数对类型(两个数值,first是键,second是值)

    1. map<int,string> mapData;
    2. mapData.insert(pair<int,string>(1,"string"));

                    方式二:insert通过一个make_pair函数构建

    1. map<int,string> mapData;
    2. mapData.insert(make_pair<int,string>(3,"string3"));

                    方式三单映射中,可以直接采用数组下标的方式进行插入

    1. map<int,string> mapData;
    2. mapData[-1]=string("string-1");

     方式三的代码等效于:

            mapData.insert(pair<int,string>(-1,"string-1"));

     注:相同的键,是采用覆盖的方式(保留最后一次更新的值)

             ②遍历:

                    方式一:迭代器遍历

                            (注:这里的*iter是pair数对类型。)

    1. for(auto iter=mapData.begin();iter!=mapData.end();iter++)
    2. {
    3. cout<<iter->first<<" "<<iter->second<<endl;
    4. //*iter指的是pair类型。
    5. }

                    方式二:

    1. for(auto v:mapData)
    2. {
    3. cout<<v.first<<" "<<v.second<<endl;
    4. }

             ③删除erase():

                         传入参数(是需要删除值对应的键)

    mapData.erase(1);

            ④其他创建方式(有一个默认比较准则参数)

    1. map<int,string> mapData;
    2. map<int ,string,less<int>> mapData1; //此创建方式,等同于第一行,从小到大。
    3. map<int,string,greater<int>>mapData2; //从大到小

            ⑤处理自定义数据类型:

             核心还是写重载函数(默认是按照键的某个属性进行比较),所以应该当键是自定义数据类型的时候,需要对键进行重载,若是用的默认的less<>比较准则,那么重载的就应该是<号

            (需要默认的构造函数,print()成员函数需要是const类型)

    1. class MM
    2. {
    3. public:
    4. MM() = default;
    5. MM(string name, int age) :name(name), age(age) {}
    6. void print() const
    7. {
    8. cout << name << "\t" << age << endl;
    9. }
    10. bool operator<(const MM& object)const
    11. {
    12. return this->name < object.name;
    13. }
    14. protected:
    15. string name;
    16. int age;
    17. };
    18. class Boy
    19. {
    20. public:
    21. Boy() = default;
    22. Boy(string name, int age) :name(name), age(age) {}
    23. void print() const
    24. {
    25. cout << name << "\t" << age << endl;
    26. }
    27. protected:
    28. string name;
    29. int age;
    30. };
    31. void testUserData()
    32. {
    33. map<MM, Boy> mbData;
    34. mbData[MM("小美", 19)] = Boy("小张", 29);
    35. mbData[MM("小美", 19)].print();
    36. mbData[MM("小丽", 20)] = Boy("小明", 18);
    37. cout << "配对信息:" << endl;
    38. for (auto v : mbData)
    39. {
    40. //容器管理自定义类型数据
    41. //v:pair<MM,Boy>
    42. //v.frist:MM
    43. //v.second:Boy
    44. v.first.print();
    45. v.second.print();
    46. }
    47. }

     4.应用:

            更好管理资源

                     例: 在加载图片资源的时候,就直接用img[键]去对应相应的资源即可。(相比数组来说,这个下标是没有任何要求。)

    1. #include<grapghic.h>
    2. map<string,IMAGE*> ima;
    3. img["墙"]=new IMAGE;
    4. img["路"]=new IMAGE;
    5. putimage(0,0,img["墙"]);
    6. putimage(0,0,img["路"]);

      五、多重映射multimap

    1.特性:

            多重映射,没有什么限制,什么样对应关系都可以插入到映射中,因为存在相同的键,所以不能采用下标法

    2.基本操作

            基本同单映射,除了不能用下标法。

                    (注:find函数找到就返回,即返回找到的第一个)

    1. void testmultimap()
    2. {
    3. //多重映射,没有什么限制,什么样对应关系都可以插入到映射中
    4. //因为存在相同的键,所以不能采用下标法
    5. multimap<int, string> mulData;
    6. mulData.insert(pair<int, string>(1, "string"));
    7. mulData.insert(pair<int, string>(12, "string1"));
    8. mulData.insert(pair<int, string>(2, "string"));
    9. mulData.insert(pair<int, string>(3, "string"));
    10. mulData.insert(make_pair<int, string>(3, "string"));
    11. for (auto v : mulData)
    12. {
    13. cout << v.first << "\t" << v.second << endl;
    14. }
    15. }

    输出:

    1       string
    2       string
    3       string
    3       string
    12      string1

    六、 initializer_list

    头文件:#include <initializer_list>

     1.引入:

            像这样的容器,初始化由后面的给的数据决定,构造函数的写法原理?

     2.利用:

            initializer_list对象(迭代器)可以存储大括号内的所有数据,并且可以一一赋值给容器中,对应的位置

                    样例代码:

                                    ①写一个类来简单模仿其实现的原理

                                    ②写一个函数来简单模仿传入多个参数的情况。

    1. #include <array>
    2. #include <list>
    3. #include <vector>
    4. #include <iostream>
    5. #include <initializer_list>
    6. using namespace std;
    7. class MM
    8. {
    9. public:
    10. MM(string a, string b, string c) :a(a), b(b), c(c) {}
    11. MM(const initializer_list<string>& list)
    12. {
    13. for (auto iter = list.begin(); iter != list.end(); iter++)
    14. {
    15. cout << *iter << endl;
    16. }
    17. }
    18. protected:
    19. string a;
    20. string b;
    21. string c;
    22. };
    23. void print(initializer_list<int> list)
    24. {
    25. for (auto iter = list.begin(); iter != list.end(); iter++)
    26. {
    27. cout << *iter << " ";
    28. }
    29. cout << endl;
    30. }
    31. int main()
    32. {
    33. array<int, 3> arrData = { 1,2,3 };
    34. vector<int> vecData1 = { 1,2,3,4 };
    35. vector<int> vecData2 = { 1,2,3,4,5 };
    36. MM mm1 = { "string1","string2","string3" };
    37. MM mm2 = { "string1" };
    38. MM mm3 = { "string1","string2" };
    39. initializer_list<int> listOne = { 1,2,3,4,5 };
    40. initializer_list<int> listTwo = { 1,2,3 };
    41. print({ 1 });
    42. print({ 1,2 });
    43. print({ 1,2,3,4 });
    44. print({ 1,2,3,4,5 });
    45. return 0;
    46. }

    七、元组tuple容器

    #include<tuple>

    1.特性:

            把任何类型的一系列数据当做一组来处理+自动增长

    2.创建方式:

    1. //方式一:
    2. tuple<string,int,int,string> wbmInfo={"bmw",18,1001,"23123"};
    3. //方式二:
    4. tuple<double,double,double>wbmscore=make_tuple(99,22,33);
    5. //方式三:
    6. tuple<string,string>value=forward_as_tuple("阿杰","阿明");

    以后结构体数组的偷懒写法:

    tuple<string,int,int,string> array[3];

     3.访问数据

            方式一:get方法

                    (不能用for循环,必须是常量)

    1. tuple<string,int,int,string> wbmInfo={"BMW"18,1001"2312"};
    2. //get方法,不能用for循环
    3. cout<<get<0>(wbmInfo)<<"\t";
    4. cout<<get<1>(wbmInfo)<<"\t";
    5. cout<<get<2>(wbmInfo)<<"\t";
    6. cout<<get<3>(wbmInfo)<<"\t";

            方式二:tie方法

                    (有点类似于流操作)

    1. tuple<string,int,int,string> wbmInfo={"BMW"18,1001"2312"};
    2. //tie方式访问数据
    3. string name;
    4. int age;
    5. int num;
    6. string tel;
    7. tie(name,age,num,tel)=wbmInfo;
    8. cout<<name<<"\t"<<age<<"\t"<<num<<"\t"<<tel<<endl;

    4.其他操作:

            将两个tuple连接起来: tuple_cat(参数1,参数2)

    1. tuple<string,int,int,string> wbmInfo={"bmw",18,1001,"23123"};
    2. tuple<double,double,double>wbmscore=make_tuple(99,22,33);
    3. auto res=tuple_cat(wbmInfo,wbmscore);

    八、了解部分(折叠参数)

    //...Args代表一个参数包
    //1.如何通过参数包定义变量 Args ...args 
    //2.如何使用参数包    args... one

    /*参数包的展开:
        1.递归的方式,自动做一个参数包的剥离过程
        2.采用列表方式进行剥离参数*/

    方式一:递归展开实现代码

    1. #include<iostream>
    2. using namespace std;
    3. //递归终止函数
    4. template <class _Ty>
    5. void print(_Ty data)
    6. {
    7. cout << data<<endl;
    8. }
    9. template <class _Ty,class ...Args>
    10. void print(_Ty data,Args ...args)
    11. {
    12. cout << data << "\t";
    13. print(args...);//递归的方式,自身调用自身。
    14. }
    15. int main()
    16. {
    17. print(1, 2, 3, 4, "string", 12.3);
    18. return 0;
    19. }

     方式二:采用列表(可增长)or数组方式进行剥离参数

    1. template <class _Ty, class ...Args>
    2. void printdata(_Ty data)
    3. {
    4. cout << data << "\t";
    5. }
    6. template<class ...Args>
    7. void printArgs(Args ...args)
    8. {
    9. //(printdata(args),0) 这是一个逗号表达式,返回的是最后一个式子的值
    10. initializer_list<int>{(printdata(args), 0)...};
    11. //也可以用数组做 等效于
    12. //int array[]={(printdata(args), 0)...};
    13. cout << endl;
    14. }
    15. int main()
    16. {
    17. printArgs(1, 2, 3, 4, "string", 12.3);
    18. return 0;
    19. }

    printdata()是中间解析函数,负责展开打印。列表数据重复调用,(,)逗号表达式,先运行printdata再将0赋值给列表。...每次调用都会剥离分离1个出来。

  • 相关阅读:
    Java零基础入门看着一篇就够了
    CAiSE 会议介绍(软件工程)- CCF B
    [SCUCTF2022]校赛Web出题笔记
    基于麻雀优化算法的路径优化问题(Matlab代码实现)
    deb包格式实例详解
    C++程序设计-第四/五章 函数和类和对象【期末复习|考研复习】
    vue使用swiper轮播组件开启loop模式点击不了问题处理
    如何使用 K3s 在您的开发机器上运行 Kubernetes 集群
    如何将Word转成PDF?试一下这个转换方法
    滚珠花键各大品牌简述
  • 原文地址:https://blog.csdn.net/zjjaibc/article/details/125420241