C++ STL set(集合)
引入:
集合和對映也是兩個常用的容器。set就是數學上的集合——每個元素最多隻出現一次。和sort一樣,自定義型別也可以構造set,但同樣必須定義“小於”運算子。
標頭檔案:
#include<set>
(當然,如果願意,你也可以用#include<bits/stdc++.h>
這個萬能庫,但是會導致記憶體巨大。。。
宣告:
set<int > s;//普通的定義(不允許元素重複)
struct rec{...};set<rec > s;//結構體
multiset<double > s;//(允許集合中元素重複)
//注意:set和multiset儲存的元素必須定義“小於號”運算子
size/empty/clear:
與vector類似,分別為元素個數、是否為空、清空。前兩者的時間複雜度為。
迭代器:
set和multiset的迭代器稱為“雙向訪問迭代器”(類似於指標),不支援“隨機訪問”,支援星號“*”解除引用,僅支援“++”和“- -”兩個與運算相關的操作。
設是一個迭代器,例如set<int > :: iterator it;
若把++,則將會指向下一個元素。這裡的“下一個”是指在元素從小到大排序的結果中,排在下一名的元素。同理,若把- -,則將會指向排在“上一個”的元素。
請注意,執行“++”和“- -”操作的時間複雜度都是
begin/end:
返回集合的首、尾迭代器,時間複雜度為。
s.begin() 是指向集合中最小元素的迭代器。
s.end() 是指向集合中最大元素的下一個位置的迭代器。換言之,就像 vector 一樣,是一個“前閉後開”的形式。因此 - -end() 是指向集合中最大元素的迭代器。
insert:
s.insert(x) 把一個元素 x 插入到集合 s 中,時間複雜度為。
在 set 中,若元素已存在,則不會重複插入該元素,對集合的狀態無影響。
下面的程式碼把 n 個整數插入有序多重集 multiset ,並從小到大輸出,時間複雜度,相當於進行了一次排序。假設 n 個整數目前儲存在陣列 a[1~n]中。
multiset<int > s;
for(int i=1;i<=n;i++)s.insert(a[i]);
for(multiset<int > :: iterator it=s.begin();it!=s.end();it++)
cout<<*id<<endl;
find:
s.find(x) 在集合s中查詢等於 x 的元素,並返回指向該指標的迭代器。若不存在,則返回 s.end() 。時間複雜度。
lower_bound/upper_bound:
這兩個函式的用法與 find 類似,但查詢的條件略有不同,時間複雜度。
s.lower_bound(x) 查詢>=x 的元素中最小的一個,並返回指向該元素的迭代器。
s.upper.bound(x) 查詢 >x 的 元 素中最小的一個,並返回指向該元素的迭代器。
erase:
設 it 是一個迭代器, s.erase(it) 從 s 中刪除迭代器 it 指向的元素,時間複雜度為。
設 x 是一個元素, s.erase(x) 從 s 中刪除所有等於 x 的元素,時間複雜度為,其中 k 為被刪除的元素個數。
如果想從 multiset 中刪掉至多1個等於 x 的元素,可以執行:
if((it==s.find(x))!=s.end())s.erase(it);
count:
s.count(x) 返回集合 s 中等於 x 的元素個數,時間複雜度為,其中 k 為元素 x 的個數。
//劉汝佳大神的書《演算法競賽入門經典》上的例題:
[UVa 10815]Andy’s First Dictionary 安迪的第一個字典
//想看題目的可以去搜題解,一般題解裡都有題目
//強烈建議不要去UVa ,因為國內翻牆太慢了。。。
//此處貼上lrj資源包裡的標程
//據lrj大神的所說,本體沒有太多的技巧,只是為了展示set的用法
//由於string已經定義了“小於”運算子,直接使用set儲存單詞集合即可
#include<iostream>
#include<string>
#include<set>
#include<sstream>
using namespace std;
set<string> dict;
string s, buf;
int main() {
while(cin >> s) {
for(int i = 0; i < s.length(); i++)
if(isalpha(s[i])) s[i] = tolower(s[i]); else s[i] = ' ';
stringstream ss(s);
while(ss >> buf) dict.insert(buf);
}
for(set<string>::iterator it = dict.begin(); it != dict.end(); ++it)
cout << *it << "\n";
return 0;
}