1、set的基础知识

  set的特性是:所有元素都会根据元素的键值自动排序,set的元素不像map那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值,实值就是键值。set不允许两个元素有相同的键值

  set的各成员函数列表如下:

1. begin():返回指向第一个元素的迭代器;end():返回指向最后一个元素的迭代器;

2.empty():如果集合为空,返回true;clear():清除所有元素;

3. erase():删除集合中的元素

  • erase(iterator) :删除定位器iterator指向的值
  • erase(first,second):删除定位器first和second之间的值
  • erase(key_value):删除键值key_value的值

4. count():返回某个值元素的个数,0或1;

5. find():返回一个指向被查找到元素的迭代器,如果没找到则返回end()。

6. insert():在集合中插入元素,插入函数的返回值不完全相同。

  • insert(key_value);将key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置。
  • inset(first,second);将定位器first到second之间的元素插入到set中,返回值是void.
  • set提供的插入函数:

    pair<iterator,bool> insert(const value_type& elem);
    iterator insert(iterator pos_hint, const value_type& elem);

  • multiset提供的插入函数:

    iterator insert(const value_type& elem);
       iterator insert(iterator pos_hint, const value_type& elem);

  返回值型别不同的原因是set不允许元素重复,而multiset允许。当插入的元素在set中已经包含有同样值的元素时,插入就会失败。所以set的返回值型别是由pair组织起来的两个值:第一个元素返回新元素的位置,或返回现存的同值元素的位置。第二个元素表示插入是否成功。

  set的第二个insert函数,如果插入失败,就只返回重复元素的位置!但是,所有拥有位置提示参数的插入函数的返回值型别是相同的。这样就确保了至少有了一个通用型的插入函数,在各种容器中有共通接口。

7. lower_bound(key_value):返回第一个大于等于key_value的定位器;upper_bound(key_value),返回最后一个大于key_value的定位器

8. size():集合中元素的数目;

9. max_size():返回集合能容纳的元素的最大限值

10. swap():交换两个集合变量,比如:c1.swap(c2);   swap(c1, c2);

11. rbegin():返回指向集合中最后一个元素的反向迭代器.; rend():返回指向集合中第一个元素的反向迭代器

12. equal_range()--返回集合中与给定值相等的上下限的两个迭代器

13. get_allocator()--返回集合的分配器

14. key_comp()--返回一个用于元素间值比较的函数

15. upper_bound()--返回大于某个值元素的迭代器

16. value_comp()--返回一个用于比较元素间的值的函数

反向迭代器:set<int>::reverse_iterator

  关于set有下面几个问题:

(1)为何map和set的插入删除效率比用其他序列容器高?

  大部分人说,很简单,因为对于关联容器来说,不需要做内存拷贝和内存移动。说对了,确实如此。set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。结构图可能如下:

  A
   / \
  B C
 / \ / \
  D E F G

因此插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍做变换后把指向删除节点的指针指向其他节点也OK了。这里的一切操作就是指针换来换去,和内存移动没有关系。

(2)为何每次insert之后,以前保存的iterator不会失效?

  iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢(当然被删除的那个元素本身已经失效了)。相对于vector来说,每一次删除和插入,指针都有可能失效,调用push_back在尾部插入也是如此。因为为了保证内部数据的连续存放,iterator指向的那块内存在删除和插入过程中可能已经被其他内存覆盖或者内存已经被释放了。即使时push_back的时候,容器内部空间可能不够,需要一块新的更大的内存,只有把以前的内存释放,申请新的更大的内存,复制已有的数据元素到新的内存,最后把需要插入的元素放到最后,那么以前的内存指针自然就不可用了。特别时在和find等算法在一起使用的时候,牢记这个原则:不要使用过期的iterator。

(3)当数据元素增多时,set的插入和搜索速度变化如何?

  如果你知道log2的关系你应该就彻底了解这个答案。在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。

  还要注意begin() 和 end()函数是不检查set是否为空的,使用前最好使用empty()检验一下set是否为空.

(4)set和multiset通常以红黑树完成,存在的优缺点?

  和所有关联式容器类似,通常使用平衡二叉树完成。事实上,set和multiset通常以红黑树实作而成。自动排序的优点是使得搜寻元素时具有良好的性能,具有对数时间复杂度。但是造成的一个缺点就是:

  • 不能直接改变元素值。因为这样会打乱原有的顺序。
  • 改变元素值的方法是:先删除旧元素,再插入新元素。
  • 存取元素只能通过迭代器,从迭代器的角度看,元素值是常数。

 2、set 比较函数、自定义比较函数

  比较函数:

   set<int> seta;               //默认是按升序方式排列元素
set<int, less<int>> setA; //按升序方式排列元素 //C++ “greater”: 未声明的标识符错误
//解决方案:在头文件中加入#include<functional>即可解决
set<int, greater<int>> setB; //按降序方式排列元素

  自定义比较函数
    (1)元素不是结构体:
        例:
        //自定义比较函数myComp,重载“()”操作符

  1. struct myComp
  2. {
  3. bool operator()(const your_type &a,const your_type &b)
  4. [
  5. return a.data-b.data>0;
  6. }
  7. }
  8. set<int,myComp>s;
  9. ......
  10. set<int,myComp>::iterator it;
#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <set>
using namespace std; class Student
{
public:
Student(char *name, int age)
{
strcpy(this->name, name);
this->age = age;
}
public:
char name[];
int age;
};
// 仿函数
struct FuncStu
{
bool operator()(const Student &left, const Student &right)
{
return (left.age < right.age);
}
};
int main()
{
Student s1("s1", );
Student s2("s1", );
Student s3("s1", ); set<Student, FuncStu> set1;
set1.insert(s1);
set1.insert(s2);
set1.insert(s3); set<Student, FuncStu>::iterator it;
for (it = set1.begin(); it != set1.end(); ++it)
{
cout << it->age << " " << it->name << endl;
} system("pause");
return ;
}

(2)如果元素是结构体,可以直接将比较函数写在结构体内。
        例:

    1. struct Info
    2. {
    3. string name;
    4. float score;
    5. //重载“<”操作符,自定义排序规则
    6. bool operator < (const Info &a) const
    7. {
    8. //按score从大到小排列
    9. return a.score<score;
    10. }
    11. }
    12. set<Info> s;
    13. ......
    14. set<Info>::iterator it;

参考博客:https://blog.csdn.net/xiajun07061225/article/details/7459206

    https://www.cnblogs.com/ChinaHook/p/6985444.html#top

C++(四十九) — set、multiset 容器的基本操作的更多相关文章

  1. C++(四十八) — string容器的基本操作

    参考博客:https://blog.csdn.net/qq_37941471/article/details/82107077 https://www.cnblogs.com/danielStudy/ ...

  2. Gradle 1.12用户指南翻译——第四十九章. Build Dashboard 插件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  3. SQL注入之Sqli-labs系列第四十七关,第四十八关,第四十九关(ORDER BY注入)

    0x1 源码区别点 将id变为字符型:$sql = "SELECT * FROM users ORDER BY '$id'"; 0x2实例测试 (1)and rand相结合的方式 ...

  4. “全栈2019”Java第四十九章:重载与重写对比详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. 第四十九个知识点:描述在IPsec和TLS后的基本想法

    第四十九个知识点:描述在IPsec和TLS后的基本想法 网络安全协议(Internet Protocol Security,IPsec)和安全传输层协议(Transport Layer Securit ...

  6. abp(net core)+easyui+efcore实现仓储管理系统——出库管理之一(四十九)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  7. Android项目实战(四十九):Andoird 7.0+相机适配

    解决方案类似: Android项目实战(四十):Andoird 7.0+ 安装APK适配 解决方法: 一.在AndroidManifest.xml 文件中添加 四大组件之一的 <provider ...

  8. Unity 游戏框架搭建 2019 (四十八/四十九) MonoBehaviourSimplify 中的消息策略完善&关于发送事件的简单封装

    MonoBehaviourSimplify 中的消息策略完善 在上一篇,笔者说,MonoBehaviourSimplify 中的消息策略还有一些小问题.我们在这篇试着解决一下. 先贴出来代码: usi ...

  9. (四十九)c#Winform自定义控件-下拉框(表格)

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

随机推荐

  1. 转载: 我如何使用 Django + Vue.js 快速构建项目

    原文链接: https://www.ctolib.com/topics-109796.html 正文引用如下 引言 大U的技术课堂 的新年第一课,祝大家新的一年好好学习,天天向上:) 本篇将手把手教你 ...

  2. SpringBoot系列教程web篇之过滤器Filter使用指南

    web三大组件之一Filter,可以说是很多小伙伴学习java web时最早接触的知识点了,然而学得早不代表就用得多.基本上,如果不是让你从0到1写一个web应用(或者说即便从0到1写一个web应用) ...

  3. asp.net core使用水晶报表问题

    背景     最近项目上遇到一个需求,要后台通过定时任务把水晶报表生成pdf文件,然后邮件发送给相关人. 技术实现思路     选用ASP.NET Core框架(基于2.2版本),通过IHostedS ...

  4. linux 把nginx加入到系统服务的方法

    linux 把nginx加入到系统服务的方法一.首先写一个shell脚本,脚本名称:nginx<pre>#! /bin/bash# chkconfig: 35 85 15 # descri ...

  5. Access to XMLHttpRequest at 'http://127.0.0.1:8000/XXXXX' from origin 'http://localhost

    Django 报错,跨域请求出现问题. 在settings.py中添加 #设置可跨域范围 CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_ALLOW_ALL = T ...

  6. 嵌入式02 STM32 实验09 独立/窗口看门狗

    一.独立看门狗和窗口看门狗 看门狗:单片机系统在外界的干扰下会出现程序跑飞的现象导致死循环,或者崩溃,看门狗电路就是为了避免这种情况的发生,看门狗的作用就是在一定的事件内(通过计数器实现)若没有收到喂 ...

  7. HTML table 表格边框

    一.总体思路: 1.表格无边框,背景颜色设置一种颜色(#DCDFE6),这样表格的边框的颜色就是表格的背景颜色: 2.单元格间距为1px,背景颜色设置为白色(#FFFFFF) // CSS table ...

  8. Python知识点总结篇(一)

    Python基础 变量 变量类型: 1.数字型 整形:int: 浮点型:float: 布尔型:bool,True和False: 复数型:complex: 2.非数字型 字符串: 列表: 元祖: 字典: ...

  9. 使用码云或GitHub搭建简单的个人网站

    视频链接:https://www.bilibili.com/video/av64294697 码云: 1.新建一个仓库      ​ 路径名会影响你的个人网站的网址(自行修改),开源(公开),其他默认 ...

  10. golang函数式编程