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. advanceInstaller安装文件的ICON

    修改以下配置 点击icon图标位置可重新选择

  2. git clone 某个链接时候报错Initialized empty Git repository in 不能克隆

    查看下是不是git是不是1.7.1版本. git --version 使用 yum -y update 更新一下. 再使用git clone 虽然还是会提示这个报错,但是可以克隆了.亲测有效. git ...

  3. DNS与ARP协议

    DNS(domain name system) DNS的作用:将域名(如baidu.com)转换为IP地址 DNS的本质是:分层的DNS服务器实现的分布式数据库: 根DNS服务器 - com DNS服 ...

  4. express脚手架重建node项目

    安装express 和express-generator cnpm install express express-generator -g express demo1 创建demo1项目, 进入项目 ...

  5. 华为交换机trunk端口更改access提示:Error: Please renew the default configurations.

    现象: 华为交换机接口由原来 trunk 接口更改 access 提示 Error: Please renew the default configurations. 解决方法: 在交换机视图模式下, ...

  6. 【ARM-Linux开发】ARM嵌入式设备Linux系统启动步骤和方式

    1). 简介 本文简单介绍ARM嵌入式设备基于嵌入式Linux操作系统时候的启动步骤和启动方式, 区别与X86平台,ARM平台下并没有一个标准的启动步骤,不同ARM SoC都会使用各自定义的boot ...

  7. opencc介绍

    1.什么是opencc? Open Chinese Convert(OpenCC)是一个开源的中文简繁转换项目,致力于制作高质量的基于统计预料的简繁转换词库.还提供函数库(libopencc).命令行 ...

  8. (CSDN 迁移) JAVA多线程实现-支持定时与周期性任务的线程池(newScheduledThreadPool)

    前几篇文章中分别介绍了 单线程化线程池(newSingleThreadExecutor) 可控最大并发数线程池(newFixedThreadPool) 可回收缓存线程池(newCachedThread ...

  9. 各手机PC品牌投屏功能连接方法

    一.iOS终端(iPhone/iPad)无线投屏: 1.将iPhone或iPad与必捷会议盒子连接至同一路由器: 2.滑动iPhone/iPad的屏幕,调出Airplay功能,选择需要投屏的主机,开始 ...

  10. Ubuntu下重启mysql

    启动mysql: 方式一:sudo /etc/init.d/mysql start 方式二:sudo service mysql start 停止mysql: 方式一:sudo /etc/init.d ...