关于set的函数与迭代器的各种操作和理解(持续更新)

本文详细介绍了C++STL中迭代器的使用,包括访问、移动、advance函数,以及通过迭代器查找元素(next,prev,find),二分查找(lower_bound,upper_bound),set的删除(erase)和插入(insert,emplace)等操作。
摘要由CSDN通过智能技术生成

目录

迭代器的访问

迭代器的移动

迭代器的 ++ 或 -- 操作

 advance()

通过迭代器查找

next( ) 或 prev( )

find()

二分查找  lower_bound()与  upper_bound()

set的删改

erase()

insert()与 emplace()

set的其他常见函数及其使用


迭代器的访问

set只能通过迭代器(iterator)访问:

set<int>::iterator it;
set<char>::iterator it;

这样我们就得到了迭代器 it ,并且我们可以通过 *it 的方式来访问 set 里的元素

一定注意!!!!!!不能像vector一样用 *(it + x) 的方式访问,但是我们可以用循环的方式访问进行访问:

    set<int>st = { 1,2,5,6,8,12 };
    //一定要注意,不支持 it < st.end() 的写法,所以我们采用it != st.end()的写法
    for (set<int>::iterator it = st.begin(); it != st.end(); it++) 
    	cout << *it << ' ';

当然,因为auto具有自动推断变量类型,所以也可以这么写(此文之后都用auto)

    set<int>st = { 1,2,5,6,8,12 };
    //这里的 it 被 auto 自动推断为 set<int>::iterator 类型
    for (auto it = st.begin(); it != st.end(); it++) 
	    cout << *it << ' ';

迭代器的移动

迭代器的 ++ 或 -- 操作

C++ STL 标准库为 set 容器配置的迭代器类型为双向迭代器。这意味着,假设 p 为此类型的迭代器,则其只能进行 ++p、p++、--p、p--、*p 操作,并且 2 个双向迭代器之间做比较,也只能使用 == 或者 != 运算符。

但是请注意!!!p += 2,p -= 5 这样的操作是不被允许的!!!!

	set<int>::iterator it;
	set<int>st = { 1,2,5,6,8,12 };
	it = st.begin();
	cout << *it << '\n';   // 1

	it++;
	cout << *it << '\n';   // 2
	it++;
	cout << *it << '\n';   // 5
	it--;
	cout << *it << '\n';   // 2

 advance()

形如:advance( it , n ) 可以将指定迭代器 it 前移或后移 n 个位置的距离(正数右移,负数左移),具体用法如下:

	set<int>::iterator it;
	set<int>st = { 1,2,5,6,8,12 };
	it = st.begin();

	cout << *it << '\n';  // 1
	advance(it, 2);
	cout << *it << '\n';  // 5
	advance(it, -1);
	cout << *it << '\n';  // 2

其实,对于set类型的迭代器,advance() 函数底层是通过重复执行 n 个 ++ 或者 -- 操作实现的。

我们需要注意的是,我们需要保证移动距离 n 应当在合适的范围内


通过迭代器查找

next( ) 或 prev( )

next( it , n ) :当 n 为正数时,其返回的迭代器将位于 it 右侧;反之,当 n 为负数时,其返回的迭代器位于 it 左侧。若不写,则默认为 n = 1 , 即右侧一个位置

prev( it , n ) :当 n 为正数时,其返回的迭代器将位于 it 左侧;反之,当 n 为负数时,其返回的迭代器位于 it 右侧。若不写,则默认为 n = 1 , 即左侧一个位置

一定注意!!!这两个函数并不会让原迭代器 it 移动,只是通过 it 去查询相应位置的新迭代器的值!!!

如要查找迭代器 it 后面 n 位置的元素:

next( it , n ) 或者 pre( it , -n )

如要查找迭代器 it 前面 n 位置的元素:

next( it , -n ) 或者 pre( it , n )

由此可见,next()和 prev()正好相反

特别的,我们需要注意n的大小以及指向的位置,因为 next() 和 prev() 自身不会检查新迭代器指向的有效性,需要我们自己来保证。

具体用法如下:

	set<int>::iterator it;
	set<int>st = { 1,2,5,6,8,12 };
	it = st.begin();
	it++; it++;
	cout << *it << '\n';   // 5
	cout << *next(it, 2) << '\n';  // 8
	cout << *prev(it, -1) << '\n';  // 6
	cout << *prev(it) << '\n';     // 2

find()

find( value ) 的形式可以返回 set 中对应值得迭代器,时间复杂度为 O( logN ),N 为 set 内得元素个数。

特别的,如果set中没有这个元素,则返回 st.end() 的迭代器

	set<int>::iterator it;
	set<int>st = { 1,2,5,6,8,12 };

    it = st.find(8);   
	cout << *it << '\n';   // 8

	it = st.find(15);   //此时相当于it被赋值为st.end()
	it--;
	cout << *it << '\n';   // 12  这里可以证明上面find返回的是st.end()

二分查找  lower_bound()与  upper_bound()

一定注意!!!!!!!

虽然 algorithm 库里面有 lower_bound() 和 upper_bound() 函数,set类型数据也可以强行调用,结果一样,但是时间复杂度是 O(n) 的

而用 set 内部自带的函数 lower_bound() 和 upper_bound() 函数 时间复杂度才是 O(logn) 的!!!

    set<int>s = { 1,3,6,9,12 };

    int temp1, temp2, temp3, temp4;
    temp1 = *lower_bound(s.begin(), s.end(), 4);//时间复杂度 O(n)
    temp2 = *upper_bound(s.begin(), s.end(), 4);//时间复杂度 O(n)
    temp3 = *s.lower_bound(4);//时间复杂度 O(logn)
    temp4 = *s.upper_bound(4);//时间复杂度 O(logn)

    cout << temp1 << '\n';// 6
    cout << temp2 << '\n';// 6
    cout << temp3 << '\n';// 6
    cout << temp4 << '\n';// 6

set的删改

erase()

三种方式进行删除 set<int>s 中的元素

①s.erase( value ) 

时间复杂度是 O( logN ) ,N为set内存放的元素个数

此函数的返回值是成功删除的个数

value为需要删除的数值,类型应为set中存放的类型(此处例子为int)

若s中没有value的值,则s不变

    set<int>s = { 1,3,6,9,12 };
    int num;
    num = s.erase(9);// 删除后s内为 1 3 6 12 , num 为 1

②s.erase( it )

时间复杂度是 O( 1 ) 

此函数的返回的是成功删除的迭代器的下一个迭代器

it 是所需要删除的元素的迭代器( it 不可以为 s.end() 不然再删除过程中会报错!),与此同时,我们也可以结合 set 中的 find() 函数来组合使用,因为 find() 函数返回的是迭代器。

    set<int>s = { 1,3,6,9,12 };
    set<int>::iterator it;

    it = s.erase(s.begin());// 删除后为 3 6 9 12 , *it 此时为 3
    s.erase(s.find(6));// 删除后为 3 9 12

③s.erase( first , last )

时间复杂度是 O( last - first ) 

此函数的返回的是成功删除最后一个迭代器的下一个迭代器,也就是 last

这里 first 是需要删除区间的起始迭代器,而 last 是需要删除的区间的末尾迭代器的下一个迭代器,从而实现删除 [ fist , last ) 区间的元素。

    set<int>s = { 1,3,6,9,12 };
    set<int>::iterator it;
    it = s.erase(++s.begin(), --s.end());//删除后s内为 1 12 , *it 为 12

    cout << *it << '\n'; // 12

insert()与 emplace()

简单来说,在 vector 或 list 中用 emplace() 效率可能会比 insert() 高些,但在 map 或 set 这种容器来说,insert() 更加适用

详细情况,可以参照此处对于 map 的 insert() 函数与 emplace() 函数的分析深入了解两函数

c++11 - What is the difference between unordered_map::emplace and unordered_map::insert in C++? - Stack Overflow

C++ Set emplace vs insert when an object is already created - Stack Overflow

C++ STL set emplace()和emplace_hint()方法详解 (biancheng.net)

set的其他常见函数及其使用

待更新...

  • 49
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值