C++中 set的用法

目录
  • 1、创建set
    • 1.1 方法1
    • 1.2 方法2
    • 1.3 方法三
  • 2、使用set
    • 2.1 insert
    • 2.2 emplace
    • 2.3 emplace_hint
    • 2.4 erase
    • 2.5 clear
    • 2.6 find
    • 2.7 count
    • 2.8 lower_bound 和 upper_bound
    • 2.9 equal_range
  • 3、总结

前言:

今天咱们继续来聊聊C++中的set。

上次的文章C++ set到底是什么遗留了一个问题没有回答,有些小伙伴有些疑问。就是为什么说set是关联式的容器,这个关联体现在哪里。

其实很简单,我们说过set的内部使用了红黑树对所有的元素进行了排序。在树结构当中,我们通常使用的都是<key, value>的形式。其中的key用来排序,value则是我们实际存储的值。只不过set有些特殊,它的valuekey是一样的,相当于是<key, key>的形式,所以它依然是关联式的容器。

今天这篇文章主要来聊聊setapi以及一些特殊的用法。

1、创建set

首先是set容器的类模板定义。

template < class T,     // 键 key 和值 value 的类型
           class Compare = less<T>,  // 指定 set 容器内部的排序规则
           class Alloc = allocator<T>  // 指定分配器对象的类型
           > class set;

其中第一个参数表示set当中元素的类型,第二个参数则是set容器内部的排序规则,第三个参数可以忽略,一般用不到。

set有3种构造函数,可以应用在不同的场景当中,我们简单来列举一下。

1.1 方法1

set<string> st;

最常规的一种,没有任何参数,直接创建。

1.2 方法2

set<string> st{"good", "bad", "medium"};

直接通过花括号枚举我们要传入set的值。

1.3 方法三

set<string> st{"good", "bad", "medium"};
set<string> st2(st);

拷贝创建,从另外一个set当中拷贝元素。

除了这三种形式的构造函数之外,还可以利用set类模板的第二个参数,传入元素排序规则来影响set中元素的排序,这勉强也算

是一种构造方法:

set<string, greater<string>> st{"good", "bad", "medium"};

我们不传入greater的排序结果是"bad", "good", "medium",当我们传入了这个参数之后,结果会变成:"medium", "good", "bad"。

这是因为我们传入的排序规则重新定义了元素的大小关系。

2、使用set

创建完了set就需要使用,使用无非增删改查。

我们先来说说增,往set里添加元素的函数有好几个,我们一个一个来说。

2.1 insert

insert函数非常简单,就直接调用,往set里插入即可。

st.insert("hhh");

但insert还可以批量插入多个元素:

st.insert({"hhh", "wow"});

2.2 emplace

emplace函数的功能和insert一样,可以往set当中插入元素。它和insert最大的区别在于emplace传入的参数并不是要插入的元素,而是构造元素需要的参数。

我这么说估计有点难理解,其实很简单,我们来对比一下就知道了。

假设我们有一个set它的类型是结构体P,当中我们重载了它的比较算子,这个先忽略。

struct P {
 int x, y;
    P(int x, int y) : x(x), y(y){};
    bool operator<(const P b) const  {
         return this->x < b.x;
    }
};

set<P> st;

如果我们要使用insert应该怎么操作呢?

P p{0, 3};
st.insert(p);

如果使用emplace函数呢,则是这样:

st.emplace(1, 23);

因为emplace的内部会替我们去调用结构体P的构造函数,使用1和23这两个参数构造出一个P的实例来存入set当中。

使用emplace可以节省掉创建实例的一步,所以通常工程当中往往大量使用emplace

emplace函数返回的结果是一个pairpair的第一个元素是set的迭代器,表示插入的元素的位置,第二个值是一个bool,表示是否插入成功。

2.3 emplace_hint

emplace函数的改进版,接受额外的参数表示插入set的位置。它的返回结果也有了一些变化,返回的是一个迭代器。

如果插入成功则返回新添加的元素,否则则指向set容器中和添加元素相同的元素。

使用emplace_hint会影响set中的有序性,一般不建议使用。

2.4 erase

说完了插入再说说删除,在set当中删除的方法只有一个就是erase,但是它却有好几种用法。

我们直接来看它的函数签名:

size_type erase (const value_type& val);
iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);

第一种方法我们传入了一个val值,也就是我们要删除的元素。

第二种方法我们传入的是一个迭代器,它会删除迭代器指向的元素。第三种方法类似,只不过我们传入的是两个迭代器,表示一个范围,它会删除这个范围内所有的元素。

第一种方法的返回值是一个整数,表示删除的元素个数。后面两种返回的都是一个迭代器,指向删除元素后面一个位置。

2.5 clear

清空set。

2.6 find

set中的查询函数,传入我们要查询的value,返回一个迭代器。

set<string>::iterator it = st.find("good");

如果成功找到则返回指向该元素的迭代器,否则指向end

2.7 count

同样是查询函数,只不过它返回的不再是迭代器,而是一个整数,表示查询到元素的个数。

int cnt = st.count("good");

2.8 lower_bound 和 upper_bound

lower_boundupper_bound严格也算是查询函数,只不过它们查询的范围。lower_bound查询的是set当中第一个大于等于val的位置,而upper_bound查询的是set中第一个严格大于val的位置。

set<string>::iterator it_low = st.lower_bound("i");
set<string>::iterator it_up = st.upper_bound("i");

同样这两个函数返回的是一个迭代器。

2.9 equal_range

这个函数返回的是一个pair,它的第一个元素是lower_bound的结果,第二个元素是upper_bound的结果。

pair<set<string>::iterator, set<string>::iterator> ret = st.equal_range("i");

3、总结

到这里,关于set常用的方法基本上就都介绍完了,除此之外还有一些其他细枝末节的方法就不赘述了。比如像是size(),max_size()等等,大家有用到去查询即可。

但是有一个疑问不知道大家有没有发现,就是我们没有介绍到修改的函数。是set不支持修改吗?

关于这个问题的答案并不是老梁故意卖关子,而是它非常复杂,一句两句很难说清楚,老梁将在下一篇文章当中好好探讨一下这个问题。如果大家有修改元素的需求,可以用erase + insert代替。

到此这篇关于C++中 set的用法的文章就介绍到这了,更多相关C++ set用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解C++ bitset用法

    C++的 bitset 在 bitset 头文件中,它是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间. 下面是具体用法 构造函数 bitset常用构造函数有四种,如下 bitset<4> bitset1; //无参构造,长度为4,默认每一位为0 bitset<8> bitset2(12); //长度为8,二进制保存,前面用0补充 string s = "100101"; bitset<10> bitset3(s); //长

  • 基于C++中setiosflags()的用法详解

    cout<<setiosflags(ios::fixed)<<setiosflags(ios::right)<<setprecision(2); setiosflags 是包含在命名空间iomanip 中的C++ 操作符,该操作符的作用是执行由有参数指定区域内的动作:   iso::fixed 是操作符setiosflags 的参数之一,该参数指定的动作是以带小数点的形式表示浮点数,并且在允许的精度范围内尽可能的把数字移向小数点右侧:   iso::right 也是se

  • C++中memset函数用法详解

    本文实例讲述了C++中memset函数用法.分享给大家供大家参考,具体如下: 功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作 用 法: void memset(void *s, char ch, unsigned n); 程序示例: #include <string.h> #include <stdio.h> #include <memory.h> int main(v

  • c++容器list、vector、map、set区别与用法详解

    c++容器list.vector.map.set区别 list 封装链表,以链表形式实现,不支持[]运算符. 对随机访问的速度很慢(需要遍历整个链表),插入数据很快(不需要拷贝和移动数据,只需改变指针的指向). 新添加的元素,list可以任意加入. vector 封装数组,使用连续内存存储,支持[]运算符. 对随机访问的速度很快,对头插元素速度很慢,尾插元素速度很快 新添加的元素,vector有一套算法. map 采用平衡检索二叉树:红黑树 存储结构为键值对<key,value> set 采用

  • C++中SetConsoleCursorPosition()移动光标函数的用法大全

    SetConsoleCursorPosition()来自于文件"windows.h",使用时记得引用此头文件. 首先说一下,这个函数的功能即是字面意思,即移动命令行中光标的位置.这里要注意的是,每次调用这个函数都是默认从左上角开始偏移,而与当前光标停留的位置无关. 然后我们剖析下这个函数,我们查看定义发现,调用这个函数需要传入两个参数,都是自定义类型,分别为 HANDLE 和 COORD. SetConsoleCursorPosition( _In_ HANDLE hConsoleOu

  • SQL Server 中 RAISERROR 的用法详细介绍

    SQL Server 中 RAISERROR 的用法 raiserror 的作用: raiserror 是用于抛出一个错误.[ 以下资料来源于sql server 2005的帮助 ] 其语法如下: RAISERROR ( { msg_id | msg_str | @local_variable } { ,severity ,state } [ ,argument [ ,...n ] ] ) [ WITH option [ ,...n ] ] 简要说明一下: 第一个参数:{ msg_id | ms

  • SeaJS中use函数用法实例分析

    本文实例讲述了SeaJS中use函数用法.分享给大家供大家参考,具体如下: 有了 define 等模块定义规范的实现,我们可以开发出很多模块.但光有一堆模块不管用,我们还得让它们能跑起来.在 SeaJS 里,要启动模块系统很简单: <script src="path/to/sea.js"></script> <script> seajs.use('./main'); </script> seajs.use 用来在页面中加载模块.通过 us

  • AngularJS中$interval的用法详解

    在AngularJS中$interval用来处理间歇性处理一些事情. 最常用的是: var app = angular.module("app",[]); app.controller("AppCtrl", function($q. $interval){ var timer = $interval(function(){ },100); timer.then(success); function success(){ console.log("done&

  • Oracle 中 decode 函数用法

    含义解释: decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下: IF 条件=值1 THEN RETURN(翻译值1) ELSIF 条件=值2 THEN RETURN(翻译值2) ...... ELSIF 条件=值n THEN RETURN(翻译值n) ELSE RETURN(缺省值) END IF decode(字段或字段的运算,值1,值2,值3) 这个函数运行的结果是,当字段或字段的运算的值等于值1时,该函数返回值2,否则返回值3  当然值1

  • Python2和Python3中print的用法示例总结

    前言 最近在学习python,对于python的print一直很恼火,老是不按照预期输出.在python2中print是一种输出语句,和if语句,while语句一样的东西,在python3中为了填补python2的各种坑,将print变为函数,因此导致python3中print的一些使用和python2很不一样.下面就来给大家详细的总结了关于Python2和Python3中print的用法,话不多说了,来一起看看详细的介绍吧. 一.Python2中的print用法 在Python2 中 prin

  • Python中max函数用法实例分析

    本文实例讲述了Python中max函数用法.分享给大家供大家参考.具体如下: 这里max函数是Python内置的函数,不需要导入math模块 # 最简单的 max(1, 2) max('a', 'b') # 也可以对列表和元组使用 max([1,2]) max((1,2)) # 还可以指定comparator function max('ah', 'bf', key=lambda x: x[1]) def comparator(x): return x[1] max('ah', 'bf', ke

  • python中pygame模块用法实例

    本文实例讲述了python中pygame模块用法,分享给大家供大家参考.具体方法如下: import pygame, sys from pygame.locals import * #set up pygame pygame.init() windowSurface = pygame.display.set_mode((500, 400), 0, 32) pygame.display.set_caption("hello, world") BLACK = (0, 0, 0) WHITE

  • C#中HttpWebRequest的用法详解

    本文实例讲述了C#中HttpWebRequest的用法.分享给大家供大家参考.具体如下: HttpWebRequest类主要利用HTTP 协议和服务器交互,通常是通过 GET 和 POST 两种方式来对数据进行获取和提交.下面对这两种方式进行一下说明: GET 方式: GET 方式通过在网络地址附加参数来完成数据的提交,比如在地址 http://www.jb51.net/?hl=zh-CN 中,前面部分 http://www.jb51.net表示数据提交的网址,后面部分 hl=zh-CN 表示附

  • MySQL数据类型中DECIMAL的用法实例详解

    MySQL数据类型中DECIMAL的用法实例详解 在MySQL数据类型中,例如INT,FLOAT,DOUBLE,CHAR,DECIMAL等,它们都有各自的作用,下面我们就主要来介绍一下MySQL数据类型中的DECIMAL类型的作用和用法. 一般赋予浮点列的值被四舍五入到这个列所指定的十进制数.如果在一个FLOAT(8, 1)的列中存储1. 2 3 4 5 6,则结果为1. 2.如果将相同的值存入FLOAT(8, 4) 的列中,则结果为1. 2 3 4 6. 这表示应该定义具有足够位数的浮点列以便

随机推荐