- ?STL 一共提供了四種與set (集合)相關的算法,分別是并集(union)、交集(intersection) > 差集 (difference)、對稱差集 (symmetricdifference
- 所謂set,可細分為數學上的定義和STL的定義兩種,數學上的set允許元素重復而未經排序,例 如 { 1,1,4,6,3} , ST L 的定義(也就是set 容器,見 5.3節) 則要求元素不得重復,并且經過排序,例如 {1,3,4,6} 。本節的四個算法所接受的set,必須是有序區間(sorted range), 元素值得重復出現。換句話說,它們可以接受 STL的 set /multiset容器作為輸入區間
- SGI STL 另外提供有 hash_set / hash_m ultiset 兩種容器,以 hashtable為底層機制(見5.8節、5.10節 ),其內的元素并未呈現排序狀態,所以雖然名稱之中也有set字樣,卻不可以應用于本節的四個算法
#include <iostream>
#include <algorithm>
#include <iterator>
#include <set>template<class T>
struct display{void operator()(const T&x){std::cout << x << ' ';}
};
int main(int argc,char* argv[]) {int ia1[] = {1,3,5,7,9,11};int ia2[] = {1,1,2,3,5,8,13};std::multiset<int>S1(ia1,ia1+6);std::multiset<int>S2(ia2,ia2+7);std::for_each(S1.begin(),S1.end(),display<int>{});std::cout << "\n";std::for_each(S2.begin(),S2.end(),display<int>{});std::cout << "\n";std::multiset<int>::iterator first1 = S1.begin();std::multiset<int>::iterator last1 = S1.end();std::multiset<int>::iterator first2 = S2.begin();std::multiset<int>::iterator last2 = S2.end();std::cout << "Union of S1 and S2: ";std::set_union(first1,last1,first2,last2,std::ostream_iterator<int>(std::cout," "));std::cout << "\n";first1 = S1.begin();first2 = S2.begin();std::cout << "Intersection of S1 and S2: ";std::set_intersection(first1,last1,first2,last2,std::ostream_iterator<int>(std::cout," "));std::cout << "\n";first1 = S1.begin();first2 = S2.begin();std::cout << "Difference of S1 and S2(S1 - S2): ";std::set_difference(first1,last1,first2,last2,std::ostream_iterator<int>(std::cout," "));std::cout << "\n";first1 = S1.begin();first2 = S2.begin();std::cout << "Symmetric difference of S1 and S2: ";std::set_symmetric_difference(first1,last1,first2,last2,std::ostream_iterator<int>(std::cout," "));std::cout << "\n";return 0;
}
6.5.1 set_ union
- 算 法 set_union可 構 造 S1和S2之并集。也就是說,它能構造出集合SI U S2,此集合內含S1 或 S2內的每一個元素。S1、S2及其并集都是以排序區間表示。返回值為一個迭代器,指向輸出區間的尾端
- 由 于 S1和 S 2 內的每個元素都不需唯一,因此,如果某個值在S1 出 現 n 次,在 S2出 現 m 次,那么該值在輸出區間中會出現max(m,n)次,其中n 個來自 s1, 其余來自S2;?在 STL set 容器內,m<=1?且 n<=1
- ?set_union是一種穩定(stable) 操作,意思是輸入區間內的每個元素的相對 順序都不會改變。set_union有兩個版本,差別在于如何定義某個元素小于另一 個元素。第一版本使用operator<進行比較,第二版本采用仿函數comp進行比較。
// 并集,求存在于[first1, last1)或存在于[first2, last2)的所有元素
// 注意,set是一種sorted range<>這是以下算法的前提
// 版本一
template<class InputIterator1,class InputIterator2,class OutputIterator>
OutputIterator set_union(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2,InputIterator2 last2,OutputIterator result){// 當兩個區間都尚未到達尾端時,執行以下操作…while (first1 != last1 && first2 != last2){// 在兩區間內分別移動迭代器。首先將元素值較小者(假設為A 區)記錄于目標區,// 然后移動A 區迭代器使之前進;同時間之另一個區迭代器不動。然后進行新一次// 的比大小、記錄小值、迭代器移動…直到兩區中有一區到達尾端。如果元素相等,// 取 S1者記錄于目標區,并同時移動兩個迭代器if (*first1 < *first2){*result = *first1;++first1;} else if (*first2 < *first1){*result = *first2;++first2;} else{//*first2 == *first1*result = *first1;++first1;++first2;}++result;// 只要兩區之中有一區到達尾端,就結束上述的while循環// 以下將尚未到達尾端的區間的所有剩余元素拷貝到目的端// 此刻的 [first1, last1)和 [first2 , last2)之中有一個是空白區間return std::copy(first1,first2,std::copy(first2,first2,result));}
}
?6.5.2 set_intersection
- 算 法 set_intersection可 構 造 SI、S 2 之交集。也就是說,它能構造出集 合 SI∩S2,此集合內同時出現于S 1 和 S 2 內的每一個元素。SI. S2及其交集都是以排序區間表示。返回值為一個迭代器,指向輸出區間的尾端。
- 由 于 S1和 S 2 內的每個元素都不需唯一,因此,如果某個值在S1出 現 n 次,在 S2出 現 m 次,那么該值在輸出區間中會出現min(m,n)次,并且全部來自 S1.在 STL set 容器內,m < 1 且 n <?1
- set_inter section是一種穩定(stable)操作,意思是輸出區間內的每個元素的相對順序都和S1內的相對順序相同。它有兩個版本,差別在于如何定義某個元素小于另一個元素.第一版本使用operator進行比較,第二版本采用仿函數comp 進行比較。
// 并集,求存在于[first1, last1)且存在于[first2, last2)的所有元素
// 注意,set是一種sorted range 這是以下算法的前提
// 版本一
template<class InputIterator1,class InputIterator2,class OutputIterator>
OutputIterator set_union(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2,InputIterator2 last2,OutputIterator result){// 當兩個區間都尚未到達尾端時,執行以下操作…while (first1 != last1 && first2 != last2){//在兩區間內分別移動迭代器,直到遇有元素值相同,暫停,將該值記錄于目標區,//再繼續移動迭代器… 直到兩區之中有一區到達尾端if (*first1 < *first2){++first1;} else if (*first2 < *first1){++first2;} else{//*first2 == *first1*result = *first1;++first1;++first2;++result;}return result;}
}
?6.5.3 set_difference
- 算 法 set_difference可構造SI> S 2 之差集。也就是說,它能構造出集合 S1 - S2,此集合內含“出現于S 1 但不出現于S2” 的每一個元素。SI. S2及其交集都是以排序區間表示。返回值為一個迭代器,指向輸出區間的尾端。
- 由于S1和 S 2 內的每個元素都不需唯一,因此如果某個值在S1 出現n 次, 在 S2出現m 次,那么該值在輸出區間中會出現max(n-m,0)次,并且全部來自S1 . 在 STL set 容器內,m < 1 且 n <?1.
- set_difference 是一種穩定(stable)操作,意思是輸出區間內的每個元素 的相對順序都和S1內的相對順序相同。它有兩個版本,差別在于如何定義某個元素小于另一個元素。第一版本使用operator進行比較,第二版本采用仿函數comp進行比較。
// 差集,求存在于[first1, last1)且不存在于[first2, last2)的所有元素
// 注意,set是一種sorted range 這是以下算法的前提
// 版本一
template<class InputIterator1,class InputIterator2,class OutputIterator>
OutputIterator set_union(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2,InputIterator2 last2,OutputIterator result){// 當兩個區間都尚未到達尾端時,執行以下操作…while (first1 != last1 && first2 != last2){// 在兩區間內分別移動迭代器。當第一區間的元素等于第二區間的元素(表示此值// 同時存在于兩區間),就讓兩區間同時前進;當第一區間的元素大于第二區間的元素,// 就讓第二區間前進;有了這兩種處理,就保證當第一區間的元素小于第二區間的// 元素時,第一區間的元素只存在于第一區間中,不存在于第二區間,于是將它// 記錄于目標區if (*first1 < *first2){*result = *first1;++first1;++result;} else if (*first2 < *first1){++first2;} else{//*first2 == *first1++first1;++first2;}return std::copy(first1,last1,result);}
}
?6.5.4 set_ symmetric_difference
- 算 法 set_symmetric_difference可構造 SI.S2之對稱差集。也就是說, 它能構造出集合 (S1-S2) U (S2-S1), 此集合內含"出現于S1但不出現于S2"以及《出現于S2但不出現于S1"的每一個元素。SI、S2及其交集都是以排序區間表示。返回值為一個迭代器,指向輸出區間的尾端.
- 由于 S1和 S 2 內的每個元素都不需唯一,因此如果某個值在S1出現 n 次, 在 S2 出 現 m 次 ,那么該值在輸出區間中會出現ln-m|次 。如 果 n > m , 輸出 區間內的最后n - m 個 元素將由S 1 復制而來,如 果 n < m 則輸出區間內的最后 m - n 個元素將由S 2 復制而來。在 STL s e t 容器內,m < 1 且 n <?1。?
- set_ symmetric_difference是 一 種 穩 定 (stable) 操 作 ,意思是輸入區間 內的元素相對順序不會被改變。它有兩個版本,差別在于如何定義某個元素小于另一個元素。第一版本使用 operator< 進行比較,第二版本采用仿函數 comp
// 對稱差集,求存在于[first1, last1)且不存在于[first2, last2)的所有元素
// 以及存在于[first2, last2)且不存在于[first1, last1)的所有元素
// 注意,上述定義只有在“元素值獨一無二”的情況下才成立.如果將set 一般化,
// 允許出現重復元素,那么 set-symmetric-difference的定義應該是:
// 如果某值在[first1 last1) 出現n次,在 [first2 last2)出現m 次,
// 那么它在result range中應該出現abs (n-m)次
// 注意,set是一種sorted range 這是以下算法的前提
// 版本一
template<class InputIterator1,class InputIterator2,class OutputIterator>
OutputIterator set_union(InputIterator1 first1,InputIterator1 last1,InputIterator2 first2,InputIterator2 last2,OutputIterator result){// 當兩個區間都尚未到達尾端時,執行以下操作…while (first1 != last1 && first2 != last2){// 在兩區間內分別移動迭代器。當兩區間內的元素相等,就讓兩區同時前進;// 當兩區間內的元素不等,就記錄較小值于目標區,并令較小值所在區間前進if (*first1 < *first2){*result = *first1;++first1;++result;} else if (*first2 < *first1){*result = *first2;++first2;++result;} else{//*first2 == *first1++first1;++first2;}return std::copy(first1,last1,std::copy(first2,last2,result));}
?
?