1. 程式人生 > >C++ STL set(集合)

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類似,分別為元素個數、是否為空、清空。前兩者的時間複雜度為O(1)

迭代器
set和multiset的迭代器稱為“雙向訪問迭代器”(類似於指標),不支援“隨機訪問”,支援星號“*”解除引用,僅支援“++”和“- -”兩個與運算相關的操作。
it是一個迭代器,例如set<int > :: iterator it;
若把it++,則it將會指向下一個元素。這裡的“下一個”是指在元素從小到大排序的結果中,排在it下一名的元素。同理,若把it- -,則it將會指向排在“上一個”的元素。
請注意,執行“++”和“- -”操作的時間複雜度都是

O(logn)。執行操作前後,務必仔細檢查,避免迭代器指向的位置超出首、尾迭代器之間的範圍。

begin/end
返回集合的首、尾迭代器,時間複雜度為O(1)
s.begin() 是指向集合中最小元素的迭代器。
s.end() 是指向集合中最大元素的下一個位置的迭代器。換言之,就像 vector 一樣,是一個“前閉後開”的形式。因此 - -end() 是指向集合中最大元素的迭代器。

insert
s.insert(x) 把一個元素 x 插入到集合 s 中,時間複雜度為O(logn)
在 set 中,若元素已存在,則不會重複插入該元素,對集合的狀態無影響。

下面的程式碼把 n 個整數插入有序多重集 multiset ,並從小到大輸出,時間複雜度O(nlogn),相當於進行了一次排序。假設 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() 。時間複雜度O(logn)

lower_bound/upper_bound
這兩個函式的用法與 find 類似,但查詢的條件略有不同,時間複雜度O(logn)
s.lower_bound(x) 查詢>=x 的元素中最小的一個,並返回指向該元素的迭代器。
s.upper.bound(x) 查詢 >x 的 元 素中最小的一個,並返回指向該元素的迭代器。

erase
設 it 是一個迭代器, s.erase(it) 從 s 中刪除迭代器 it 指向的元素,時間複雜度為O(logn)
設 x 是一個元素, s.erase(x) 從 s 中刪除所有等於 x 的元素,時間複雜度為O(k+logn),其中 k 為被刪除的元素個數。
如果想從 multiset 中刪掉至多1個等於 x 的元素,可以執行:

if((it==s.find(x))!=s.end())s.erase(it);

count
s.count(x) 返回集合 s 中等於 x 的元素個數,時間複雜度為O(k+logn),其中 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;
}