ACM中好用的SET

SET 集合

百度百科中說集合中的元素有三個特徵:php

1.肯定性(集合中的元素必須是肯定的) 2.互異性(集合中的元素互不相同。例如:集合A={1,a},則a不能等於1) 3.無序性(集合中的元素沒有前後之分。)ios

而STL中的集合set ,按照定義保證了元素的肯定性,互異性,神奇的是其中的元素倒是有序的c++


卓越的前輩們在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, 每一個位置的珠子可能有不一樣的種類,
規定連續的一段中若是存在兩個珠子種類相同,則稱爲好珠子段,問最多有多少好珠子段,並打印段的位置。
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;
}

SET的遍歷

這裏用到了迭代器的相關知識,學完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

相關文章
相關標籤/搜索