理论: STL(1): set

来源:互联网 发布:观山4字能值多少钱知乎 编辑:程序博客网 时间:2024/06/05 12:39

原文出处:http://blog.csdn.net/chaiwenjun000/article/details/50561775

SET 集合

百度百科中说集合中的元素有三个特征:
1.确定性(集合中的元素必须是确定的)
2.互异性(集合中的元素互不相同。例如:集合A={1,a},则a不能等于1)
3.无序性(集合中的元素没有先后之分。)
而STL中的集合set ,按照定义保证了元素的确定性,互异性,神奇的是其中的元素却是有序的!

卓越的前辈们在c++里为我们封装好了set,只需要在头文件里

#include<set>  using namespace std;  

就可以方便的使用了。

如何定义一个set?

set<_type> _name;  

_type集合元素的类型 ,除了基本类型也可以是自定义类型。
_name 该集合的名称

我们以int为例做一下示范

先介绍几个set常用的函数
.insert(v) //插入一个元素v
.erase(v) //删除一个元素v (可以是元素的值,也可以是迭代器(后面会有介绍))
.empty() //判断是否为空
.count(v)//判断 v出现了几次

#include<set>  using namespace std;  int main(){      set<int>st; //定义了一个int类型的集合,名称为st      st.insert(1); st.insert(7);    st.insert(4);      if(!st.empty())          printf("yes\n");      if(st.count(1)) printf("1yes\n"); else printf("1no\n");      if(st.count(2)) printf("2yes"); else printf("2no\n");  }  

·
·

SET的应用

有了这几个函数,set就可以做很多事了,其中最常用的就是 判断一个数是否出现过。
set内部使用红黑树实现,也就是平衡的二叉树查找树,其插入删除查找的效率是稳定的O(logn)。这个效率是很高的,当然设计合适的hash函数速度更快O(1),但对于一般的问题这个已经足够了,而且简单书写。

下面就以昨天CF第三题为例做下示范
http://codeforces.com/contest/620/problem/C

长度为n的珠子链, 从左到右位置标号1~n, 每个位置的珠子可能有不同的种类,
规定连续的一段中如果存在两个珠子种类相同,则称为好珠子段,问最多有多少好珠子段,并打印段的位置。
方法
直接贪心,遇到两个相同的珠子,就记录下来位置。然后将之前的标记清空。
标记方法? ai 范围 1≤ ai ≤ 10^9,开那么大的数组显然不行,而且清空也麻烦
直接用set即可!
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片

#include <iostream>  #include <cstdio>  #include <cstring>  #include <algorithm>  #include <set>  using namespace std;  const int maxn = 100000*4;  int arr[maxn];  int cnt[maxn];  set<int>st;  int main()  {      int t;      scanf("%d",&t);      int c = 0;      for(int i=0;i<t;i++){          scanf("%d",&arr[i]);          if(!st.count(arr[i])) //没有标记过的              st.insert(arr[i]);          else          {              st.clear(); //清空set              cnt[c++] = i+1; //记录标记的位置(出现第二次的珠子位置)          }      }      cnt[c-1] = t;       if(c == 0)          printf("-1\n");      else{          printf("%d\n",c);          int l = 1;          for(int i=0;i<c;i++){              printf("%d %d\n",l,cnt[i]);              l = cnt[i]+1;          }      }      return 0;  }  

·
·
·

SET的遍历

这里用到了迭代器的相关知识,学完C++后再去深究,这里知道怎么用就行了。
前面说了set中的元素是有序的,那么我们来遍历一下。
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片

#include<set>  using namespace std;  int main(){      set<int>st; //定义了一个int类型的集合,名称为st      st.insert(1); st.insert(7);    st.insert(4);      st.insert(0);      for(set<int>::iterator it = st.begin();it!=st.end();++it){          printf("%d ",*it);      }  }  

可以看出迭代器的使用和指针类似 , 也是通过解引用运算符 *it来获取值,也可以通过++ – 移动。
也可以单个取出元素

set<int>::iterator it = st.begin();  printf("%d\n",*it);  

注意这里的.begin()代表了set中的首元素位置,而.end()代表的是尾元素位置的下一个位置。
STL中很多容器都是这样的左闭右开区间,不用去深究。

TIPS: 对于需要集合中存在重复元素的情况,STL中也封装的multiset,用法和set几乎一样,这里不再赘述。
推荐的习题:按照各路大牛博客中的STL分类去刷就行,我推荐一个多么痛的领悟,第六届山东省ACM程序设计竞赛B题
题目链接:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=3252

原文出处:http://blog.csdn.net/chaiwenjun000/article/details/50561775

0 0