• c++ 常用STL 之set


    在文章c++ 常用STL 之vector_kangshuangzhu的博客-CSDN博客

    中介绍了序列容器,并且系统介绍了vector的用法。不难发现,无论是哪种序列式容器,其存储的都是 C++ 基本数据类型(诸如 int、double、float、string 等)或使用结构体自定义类型的元素。例如,如下是一个存储 int 类型元素的 vector 容器:

    std::vector primes {2, 3, 5, 7, 11, 13, 17, 19};
    关联式容器则大不一样,此类容器在存储元素值的同时,还会为各元素额外再配备一个值(又称为“键”,其本质也是一个 C++ 基础数据类型或自定义类型的元素),它的功能是在使用关联式容器的过程中,如果已知目标元素的键的值,则直接通过该键就可以找到目标元素,而无需再通过遍历整个容器的方式。

    常用的关联式容器包括set map

    下面会着重介绍一下set

    set  定义在 头文件中,使用该容器存储的数据,各个元素键和值完全相同,且各个元素的值不能重复(保证了各元素键的唯一性)。该容器会自动根据各个元素的键(其实也就是元素值)的大小进行升序排序(调用 std::less)。

    set的存储方式是平衡二叉树,所以可以快速实现有序的插入元素

     这里仍然从初始化,增,删,改,查5个方面入手,

    初始化:

    set的初始化和vector比较像,可以空初始化;赋值初始化;拷贝其他set,但是拷贝初始化的时候拷贝的一定要是另一个set,如果是其他的容器则会报错。

    1. std::vector<int> my_vec = {1,2,3,3,4,3,6};
    2. std::set<int> s1; // 初始化一个空set
    3. std::set<int> s2 = {4,5,3,6,2,7}; // 赋值初始化一个set
    4. std::set<int> s3(s2); // 拷贝s2的元素
    5. std::set<int> s3(my_vec); // 报错
    6. std::set<int> s4(s2.begin(),++s2.begin()); // 取某一段内存的数据初始化
    7. std::set<int> s4(s2.begin(),s2.begin()+3); //报错,set迭代器不支持这种运算
    8. std::set<int> s5(my_vec.begin(), my_vec.end()); // 取某一段内存的数据初始化
    9. std::set<int> s6 = {my_vec.begin(), my_vec.end()}; // 取某一段内存的数据初始化

    应用最灵活的还是用迭代器初始化,同样的,用迭代器初始化,不要求迭代器是set的迭代器,任何迭代器都可以。

    应该格外注意的是set的迭代器不支持s.begin()+3 这种运算,但是却支持s.begin()++ 和 ++ s.begin() 。后面如果找到原因会在这里补上。

    查:

    因为元素是有序的插入到set中的,所以,set是无序的,不能用下表或者at函数来取某一个值。

    find 查询set是否包含某一个元素,如果存在则返回迭代器,如果没有则返回end

    1. std::set<int> s2 = {4,5,3,6,2,7}; // 赋值初始化一个set
    2. auto k = s2.find(3);
    3. std::cout << "(k == s2.end()) " << (k == s2.end()) << std::endl;
    4. auto s = s2.find(30);
    5. std::cout << "(s == s2.end()) " << (s == s2.end()) << std::endl;
    6. 输出
    7. (k == s2.end()) 0
    8. (s == s2.end()) 1

    size()  获取set的大小

    empty()set是否为空

    1. std::set<int> s2 = {4,5,3,6,2,7}; // 赋值初始化一个set
    2. std::cout << "set size " << s2.size() << std::endl;
    3. 输出
    4. set size 6

    遍历set

    set的遍历方式有两种。因为set时无需集合,所以不能通过下标的方式遍历。

    1. std::set<int> s2 = {4,5,3,6,2,7}; // 赋值初始化一个set
    2. for (auto i: s2){
    3. std::cout << i << " ";
    4. }
    5. for(auto i = s2.begin(); i != s2.end(); i++){
    6. std::cout << *i << " ";
    7. }
    8. for(auto i = s2.begin(); i < s2.end(); i++){ //报错
    9. std::cout << *i << " ";
    10. }

    set的第二种遍历有一个地方需要注意,终止循环的条件不能写成 

    i < s2.end()

    而要写成

    i != s2.end()

    set提供一个insert函数用于新增元素,因为set会对元素自动排序,新增元素的时候无所谓插入位置。虽然insert 可以指定插入位置,但插入后会自动排序,所以指定的插入位置没有用

    1. std::set<int> s2 = {4,5,3,6,2,7};
    2. s2.insert(10);
    3. for (auto i: s2){
    4. std::cout << i << " ";
    5. }
    6. s2.insert(s2.begin(), 20);
    7. for(auto i = s2.begin(); i != s2.end(); i++){
    8. std::cout << *i << " ";
    9. }
    10. 输出
    11. 2 3 4 5 6 7 10
    12. 2 3 4 5 6 7 10 20

    这种指定插入位置的用法可能会逐渐废弃,所以不推荐使用

    当然insert还是支持插入一个迭代器的,在插入迭代器的时候,不能指定插入位置。例如

    1. std::set<int> s2 = {4,5,3,6,2,7};
    2. std::set<int> s3({-1,-2,-3,-4});
    3. s2.insert({10,20,30});
    4. for (auto i: s2){
    5. std::cout << i << " ";
    6. }
    7. s2.insert(s3.begin(), s3.end());
    8. for(auto i = s2.begin(); i != s2.end(); i++){
    9. std::cout << *i << " ";
    10. }
    11. 输出
    12. 2 3 4 5 6 7 10 20 30
    13. -4 -3 -2 -1 2 3 4 5 6 7 10 20 30

    删:

    clear(),删除set 所有值

    set的删除函数时erase,因为set的元素有唯一性,所以对于基本数据结构可以直接输入一个值进行删除

    1. std::set<int> s2 = {4,5,3,6,2,7};
    2. s2.erase(6);
    3. for (auto i: s2){
    4. std::cout << i << " ";
    5. }
    6. 输出
    7. 2 3 4 5 7

    当然也可以通过迭代器删除,但是因为set迭代器不支持 begin()+2 以及 < , > , <=,  >= 这些操作。所以想删除某一段数据会比较繁琐。

    1. std::set<int> s2 = {4,5,3,6,2,7};
    2. auto it = s2.find(5);
    3. s2.erase(it,s2.end());
    4. for (auto i: s2){
    5. std::cout << i << " ";
    6. }
    7. 输出
    8. 2 3 4

    swap 与 vector相同,可以看文章c++ 常用STL 之vector_kangshuangzhu的博客-CSDN博客

  • 相关阅读:
    函数式接口和方法引用
    7-156 找最小的字符串
    python — 面向对象【1】
    Polygon Miden VM中的哈希函数对比
    「MySQL高级篇」MySQL存储引擎
    环境配置 | 图文VS2022配置OpenCV,Dlib
    java基础题——二维数组的基本应用2
    Google重磅发布Go语言编码规范
    C#重启 --- 数据类型
    探索UI设计|栅格系统的深入分析和应用
  • 原文地址:https://blog.csdn.net/kangshuangzhu/article/details/127625107