百度百科中说集合中的元素有三个特征:php
1.肯定性(集合中的元素必须是肯定的) 2.互异性(集合中的元素互不相同。例如:集合A={1,a},则a不能等于1) 3.无序性(集合中的元素没有前后之分。)ios
而STL中的集合set ,按照定义保证了元素的肯定性,互异性,神奇的是其中的元素倒是有序的!c++
卓越的前辈们在c++里为咱们封装好了set,只须要在头文件里数组
#include<set> using namespace std;就能够方便的使用了。
set<_type> _name; _type集合元素的类型 ,除了基本类型也能够是自定义类型。 _name 该集合的名称
先介绍几个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内部使用红黑树实现,也就是平衡的二叉树查找树,其插入删除查找的效率是稳定的O(logn)。这个效率是很高的,固然设计合适的hash函数速度更快O(1),但对于通常的问题这个已经足够了,并且简单书写。
下面就以昨天CF第三题为例作下示范
http://codeforces.com/contest/620/problem/C
长度为n的珠子链, 从左到右位置标号1~n, 每一个位置的珠子可能有不一样的种类,
规定连续的一段中若是存在两个珠子种类相同,则称为好珠子段,问最多有多少好珠子段,并打印段的位置。
spa
方法
直接贪心,遇到两个相同的珠子,就记录下来位置。而后将以前的标记清空。
标记方法? ai 范围 1≤ ai ≤ 10^9,开那么大的数组显然不行,并且清空也麻烦
直接用set便可!
设计
#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; }
这里用到了迭代器的相关知识,学完C++后再去深究,这里知道怎么用就好了。指针
前面说了set中的元素是有序的,那么咱们来遍历一下。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几乎同样,这里再也不赘述。blog
推荐的习题:按照各路大牛博客中的STL分类去刷就行,我推荐一个多么痛的领悟,第六届山东省ACM程序设计竞赛B题
题目连接:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=3252