当前位置:   article > 正文

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

获取set的迭代器

目录

迭代器的访问

迭代器的移动

迭代器的 ++ 或 -- 操作

 advance()

通过迭代器查找

next( ) 或 prev( )

find()

二分查找  lower_bound()与  upper_bound()

set的删改

erase()

insert()与 emplace()

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


迭代器的访问

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

  1. set<int>::iterator it;
  2. set<char>::iterator it;

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

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

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

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

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

迭代器的移动

迭代器的 ++ 或 -- 操作

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

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

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

 advance()

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

  1. set<int>::iterator it;
  2. set<int>st = { 1,2,5,6,8,12 };
  3. it = st.begin();
  4. cout << *it << '\n'; // 1
  5. advance(it, 2);
  6. cout << *it << '\n'; // 5
  7. advance(it, -1);
  8. 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() 自身不会检查新迭代器指向的有效性,需要我们自己来保证。

具体用法如下:

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

find()

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

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

  1. set<int>::iterator it;
  2. set<int>st = { 1,2,5,6,8,12 };
  3. it = st.find(8);
  4. cout << *it << '\n'; // 8
  5. it = st.find(15); //此时相当于it被赋值为st.end()
  6. it--;
  7. 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) 的!!!

  1. set<int>s = { 1,3,6,9,12 };
  2. int temp1, temp2, temp3, temp4;
  3. temp1 = *lower_bound(s.begin(), s.end(), 4);//时间复杂度 O(n)
  4. temp2 = *upper_bound(s.begin(), s.end(), 4);//时间复杂度 O(n)
  5. temp3 = *s.lower_bound(4);//时间复杂度 O(logn)
  6. temp4 = *s.upper_bound(4);//时间复杂度 O(logn)
  7. cout << temp1 << '\n';// 6
  8. cout << temp2 << '\n';// 6
  9. cout << temp3 << '\n';// 6
  10. cout << temp4 << '\n';// 6

set的删改

erase()

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

①s.erase( value ) 

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

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

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

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

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

②s.erase( it )

时间复杂度是 O( 1 ) 

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

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

  1. set<int>s = { 1,3,6,9,12 };
  2. set<int>::iterator it;
  3. it = s.erase(s.begin());// 删除后为 3 6 9 12 , *it 此时为 3
  4. s.erase(s.find(6));// 删除后为 3 9 12

③s.erase( first , last )

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

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

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

  1. set<int>s = { 1,3,6,9,12 };
  2. set<int>::iterator it;
  3. it = s.erase(++s.begin(), --s.end());//删除后s内为 1 12 , *it 为 12
  4. 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的其他常见函数及其使用

待更新...

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/858833
推荐阅读
相关标签
  

闽ICP备14008679号