百度百科中說集合中的元素有三個特徵: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