set就是數學上的集合——每一個元素最多隻能出現一次。ios
【關於set】
set是關聯式容器。set做爲一個容器也是用來存儲同一數據類型的數據類型,而且能從一個數據集合中取出數據,在set中每一個元素的值都惟一,並且系統能根據元素的值自動進行排序。應該注意的是set中數元素的值不能直接被改變。C++ STL中標準關聯容器set, multiset, map, multimap內部採用的就是一種很是高效的平衡檢索二叉樹:紅黑樹,也稱爲RB樹(Red-Black Tree)。RB樹的統計性能要好於通常平衡二叉樹,因此被STL選擇做爲了關聯容器的內部結構。less
【關聯型容器概述】ide
在學習序列式容器時,咱們知道,容器中元素的順序都是由程序決定的,程序能夠隨意指定新元素的插入位置,而對於關聯型容器,它的全部元素都是通過排序的,關聯型容器都是有序的。它的每個元素都有一個鍵(key),容器中的元素是按照鍵的取值升序排列的。
關聯型容器內部實現爲一個二叉樹,在二叉樹中,每一個元素都有一個父節點和兩個子節點。左子樹的全部元素都比本身小,右子樹的全部元素都比本身大。函數
A
/ \
B C
/ \ / \
D E F G性能
關聯型容器內部結構都是以這種一叉樹結構實現, 這也使得它能夠高效地查找容器中的每個元素,但卻不能實現任意位置的操做。
標準庫提供了四種關聯型容器: set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射),其中set與multiset 包含在頭文件set中,map與multimap包含在頭文件map中。
學習
set與muliset的區別在因而否容許有重複元素,其餘用法都很類似,所以將這兩種容器放在一塊兒進行講解, 接下來咱們就分 別講解集合對象的建立及其經常使用的操做方法。spa
【set、muliset中經常使用的方法】
一、建立對象。code
set與muliset中都重載了不一樣的構造函數,所以能夠以不一樣的方式定義集合,set 集合的定義方式以下所示:
set<T> s; //建立一個空的set集合,默認升序排列
set<T, op> s; //建立一個空的set集合,按op規則排序
set<T> s(begin, end) ; //建立一個集合,用[begin, end]區間爲其 初始化
set<T,op> s (begin, end) ; //建立集合,用[begin, end]區間爲其初始化並按op規則排序
set<T> s(s1) ; //建立一個空的set集合,用另外一個集合s1初始化對象
set集合提供了五種重載構造函數,接下來咱們分別用這五種方式定義不一樣的集合,代碼
以下所示:
set<char> s1;
set<int, greater<int>()> s2;
set<float> s3(begin, end) ;
set<string,greater<string>()> s4 (begin, end) ;
set<int> s5(s2) ;
注:
geater<T>從大到小
less<T> 從小到大blog
上述代碼分別用不一樣的方式定義了char、int等類型的集合,其中集合s2與s4中greater<T>則是排序規則,意指從大到小的順序排列,若是沒有排序規則,則默認規則是less<T>,意爲從小到大排序,這是STL中定義的函數對象( functor),包含在頭文件functional中
與set集合同樣,multiet也重載了這五種構造函數,接下來用這五種方式分別定史不一樣的multiset集合對象,代碼以下所示:
multiset <char> ms1 ;
multiset <int, greater<int> ()> ms2;
multiset <float>ms3 (begin, end) ;
multiset <string, greater<string>()> ms4 (begin, end) ;
multiset <int> ms5(s2) ;
上述代碼分別用五種不一樣的方式定義了五個multiset 集合對象,其定義中的參數與set集合同樣,這裏就再也不贅述。
二、集合的大小,元素的查找和統計。
s.size(); //返回容器中元素的數目
s.max_size(); //返回容器中可容納的最大元素數量
s.empty(); //判斷容器是否爲空
上述函數 調用中的s指集合容器,如無特殊說明,則s既能夠是set容器也能夠是multiset容器,即兩個容器都提供了這樣的函數。
s.find(); //查找函數
s.count(); //統計個數的函數
find( )函數的功能是返回key元素的位置,返回值是迭代器類型。count( )函數的功能是返回元素elem的個數,對於set集合來講,要麼是0要麼是1,而對於multiset來講,值可能大於1。
三、獲取頭尾部元素。
s.begin(); //返回容器中收元素的位置
s.end(); //返回容器中最後一個元素字後的迭代器
四、插入和刪除元素。
s.insert(elem); //在容器中插入元素elem
s.insert(pos, elem); //在pos位置插入元素elem
s.insert(begin, end); //在容器中插入[begin,end]區間的值
對於set容器來講,第一種形式的insert( )調用的返回值是pair<iterator, bool>對象,其第一個參數iterator 是迭代器,指示元素插入的位置;第二個參數bool類型的值表明元素是否插入成功。
這是由於set容器中不容許存在重複的元素,若是要插入一個容器中已存在的元素,則插入操做會失敗,而pair中的bool值就是標識插入是否成功,而multiset不存在這樣的狀況,所以multiset返回的是-個 iterator。
set與multiset提供的erase( )函數也有幾種實現形式,其函數調用形式以下所示:
s.erase (pos) ; //刪除pos位置上的元素
s.erase (begin, end) ; //刪除[begin, end) 區間上的元素
s.erase (elem) ; / /刪除元素elem
調用erase()函數能夠刪除某一個位置 上的元素,能夠刪除指定的元素,也能夠刪除指定範圍的元素。
五、其餘
equal_range() 返回一對定位器,分別表示第一個大於或等於給定關鍵值的元素和 第一個大於給定關鍵值的元素,這個返回值是一個pair類型,若是這一對定位器中哪一個返回失敗,就會等於end()的值。具體這個有什麼用途我還沒遇到過~~~
find() ,返回給定值值得定位器,若是沒找到則返回end()。
lower_bound(key_value) ,返回第一個大於等於key_value的定位器
upper_bound(key_value),返回最後一個大於等於key_value的定位器
【示例代碼】
1 #include <iostream> 2 #include <set> 3 #include <functional> 4 using namespace std; 5 int main() 6 { 7 set<int, greater<int>> s; //建立一個set容器,元素按降序排列 8 multiset<char> ms; //建立一個multiset容器 9 cout << "s能容納的最大元素數量" << s.max_size() << endl; 10 cout << "ms能容納的最大元素數量" << ms.max_size() << endl; 11 //向s中插入元素 12 pair<set<int>::iterator, bool> ps; 13 ps = s.insert(12); 14 if (ps.second == true) 15 cout << "insert success" << endl; 16 s.insert(39); 17 s.insert(32); 18 s.insert(26); 19 //向ms中插入元素 20 ms.insert('a'); 21 ms.insert('z'); 22 ms.insert('T'); 23 ms.insert('u'); 24 ms.insert('u'); 25 //輸出兩個容器中的元素 26 set<int>::iterator its; //建立s容器的迭代器,用於獲取元素 27 cout << "s容器中元素:"; 28 for (its = s.begin(); its != s.end(); its++) 29 cout << *its << " "; 30 cout << endl; 31 multiset<char>::iterator itms; //建立ms容器的迭代器 32 cout << "ms容器中元素:"; 33 for (itms = ms.begin(); itms != ms.end(); itms++) 34 cout << *itms << " "; 35 cout << endl; 36 37 //查找兩個容器中頭尾元素 38 cout << "s頭元素: " << *s.begin() << endl; 39 cout << "ms尾元素: " << *(--ms.end()) << endl; 40 //查找ms容器中u元素出現的次數 41 cout << "ms容器中u元素出現的次數:" << ms.count('u') << endl; 42 system("pause"); 43 return 0; 44 }
運行結果以下
樣例中建立了一個set容器s和一個multiset容器ms,其中容器s中的元素是按降序排列,代碼9~ 10行調用max_ size( )函數分別算出兩個容器的最大容量,代碼12~24行分別調用insert( )函數向兩個容器中插入元素,其中ms容器中插入了重複的元素u,代碼26~35行分別建立相應的迭代器輸出容器中的元素,由圖8-14可知,s中的元素按降序排列,ms中的元素按升序排列。代碼37~ 38行分別調用begin()與end( )函數輸出s的頭元素和ms的尾元素,由運行結果可知,兩個元素輸出成功。代碼41行調用count( )函數輸出ms容器中u元素的個數,由運行結果可知,ms容器中u元素有兩個。
最後咱們用一到題來體會set的用處。
【問題描述】輸入一個文本,找出全部不一樣的單詞(連續的字母序列),按字典序從小到大輸出。單詞不區分大小寫。
【樣例輸入】
Adventures in Disneyland
Two blondes were going to Disneyland when they came to a fork in the
road. The sign read: "Disneyland Left."
So they went home.
【樣例輸出】
a
adventures
blondes
came
disneyland
fork
going
home
in
left
read
road
sign
so
the
they
to
two
went
were
when
【代碼以下】
1 #include<iostream> 2 #include<string> 3 #include<set> 4 #include<sstream>//stringstream要包含的頭文件 5 using namespace std; 6 set<string> dict;//string 集合 7 8 int main() 9 { 10 11 string s, buf; 12 while (cin >> s) 13 { 14 for (int i = 0; i < s.length(); i++) 15 if (isalpha(s[i]))//是不是字母 16 s[i] = tolower(s[i]);//變成小寫 17 else 18 s[i] = ' '; 19 stringstream ss(s); 20 //stringstream是字符串流。 21 //它將流與存儲在內存中的string對象綁定起來。 22 //在多種數據類型之間實現自動格式化。 23 while (ss >> buf) 24 dict.insert(buf);//插入元素 25 } 26 for (set<string>::iterator it = dict.begin(); it != dict.end(); ++it)//循環輸出 27 cout << *it << "\n"; 28 29 system("pause"); 30 return 0; 31 }