set和multiset会根据特定的排序准则,自动将元素排序。两者不同处在于multiset允许元素重复而set不允许。
一、集和多集(set 和multiset 容器类)
在使用set和multiset之前,先必须包含头文件<set>
#include <set>
在其中,set和multiset被定义为命名空间std内的class template:
namespace std { template<class T, <class Compare = less<T>, <class Allocator = allocator<T> > class set; template<class T, <class Compare = less<T>, <class Allocator = allocator<T> > class multiset; }第一个template参数当做元素的value。
构造:
explicit set(const Compare&=compare());如:set<int,less<int> > set1;
less<int>是一个标准类,用于形成升序排列函数对象。降序排列是用greater<int>。
Template<class InputIterator> set(InputIterator, InputIterator, const Compare&=compare());如:set<int ,less<int> >set2(vector1.begin(),vector1.end());
set<int> c; set<int> c(op); set<int> c1(c2); set<int> c(beg,end,op); c.size();//集合中元素的数目 c.empty();//如果集合为空,返回true(真) c.max_size();//返回集合能容纳的元素的最大限值 c.count(elem);//返回某个值元素的个数 c.find(elem);//返回一个指向被查找到元素的迭代器 c.lower_bound(elem);//返回指向大于(或等于)某值的第一个元素的迭代器 c.upper_bound(elem);//返回大于某个值元素的迭代器 c.equal_range(elem);//返回集合中与给定值相等的上下限的两个迭代器 c.swap(c1)或全局函数swap(c,c1); //交换两个集合变量 c.begin();//返回指向第一个元素的迭代器 c.end();//返回指向最后一个元素之后的迭代器,不是最后一个元素 c.rbegin();//返回指向集合中最后一个元素的反向迭代器 c.rend();//返回指向集合中第一个元素的反向迭代器 c.insert(elem);//在集合中插入元素 c.insert(pos,elem); c.insert(beg,end); c.erase(elem);//返回移除元素个数,删除集合中的元素 c.erase(pos);//无返回值 c.erase(beg,end);//无返回值 c.clear();//清除所有元素 //set提供如下接口 pair<iterator, bool> insert(const value_type &elem); iterator insert(iterator pos_hint, const value_type &elem); //multiset提供如下接口 iterator insert(const value_type &elem); iterator insert(iterator pos_hint, const value_type &elem); ////////////////// typedef set<int, greater<int> > IntSet; typedef multiset<int, greater<int> > IntSet;
get_allocator() 返回集合的分配器
key_comp() 返回一个用于元素间值比较的函数
value_comp() 返回一个用于比较元素间的值的函数
集合操作:
std::set_intersection() ;//这个函数是求两个集合的交集。 std::set_union() ;//求两个集合的并集 std::set_difference(); //差集 std::set_symmetric_difference(); //得到的结果是第一个迭代器相对于第二个的差集并 上第二个相当于第一个的差集 struct compare{ bool operator ()(string s1,string s2){ return s1>s2; }///自定义一个仿函数 }; std::set<string,compare> s; string str[10]; string *end = set_intersection(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//求交集,返回值指向str最后一个元素的尾端 end = std::set_union(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//并集 end = std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//s2相对于s1的差集 end = std::set_difference(s2.begin(),s2.end(),s.begin(),s.end(),str,compare());//s1相对于s2的差集 end = std::set_symmetric_difference(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//上面两个差集的并集
二、应用实例
#include <iostream> #include <set> using namespace std; int main(int argc, char **argv) { //type of the collection : sets //no duplicates //elements are integral values // descending order typedef set<int, greater<int> > IntSet; //empty set container IntSet coll; //insert elements in random order coll.insert(4); coll.insert(3); coll.insert(5); coll.insert(1); coll.insert(6); coll.insert(2); coll.insert(5); //iterate over all elements and print them IntSet::iterator pos; for (pos = coll.begin(); pos != coll.end(); ++ pos) { cout<< *pos<<"\n"; } //insert 4 again and process return value pair<IntSet::iterator, bool> status = coll.insert(4); if (status.second) { cout<<"4 inserted as element " <<distance(coll.begin(), status.first) + 1 <<endl; } else { cout<<"4 already exists"<<endl; } copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout<<endl; //assign elements to anthor set with ascending order //set<int> coll2(coll.begin(), coll.end()); //copy(coll2.begin(), coll2.end(), ostream_iterator<int>(cout, " ")); //remove all the elements up to element with 3 coll.erase(coll.begin(), coll.find(3)); copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout<<endl; //remove all elements with value 5 int num = coll.erase(2); cout<<num<<" elements removed "<<endl; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout<<endl; cout<<endl; return 0; }运行结果:
#include <iostream> #include <set> #include <string> #include <algorithm> using namespace std; struct compare { bool operator() (string s1,string s2) { return s1>s2; }///自定义一个仿函数 }; int main() { typedef std::set<string,compare> _SET; _SET s; s.insert(string("sfdsfd")); s.insert(string("apple")); s.insert(string("english")); s.insert(string("dstd")); cout<<"s1:"<<endl; std::set<string,compare>::iterator it = s.begin(); while(it!=s.end()) cout<<*it++<<" "; cout<<endl<<"s2:"<<endl; _SET s2; s2.insert(string("abc")); s2.insert(string("apple")); s2.insert(string("english")); it = s2.begin(); while(it!=s2.end()) cout<<*it++<<" "; cout<<endl<<endl; string str[10]; string *end = set_intersection(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//求交集,返回值指向str最后一个元素的尾端 cout<<"result of set_intersection s1,s2:"<<endl; string *first = str; while(first<end) cout <<*first++<<" "; cout<<endl<<endl<<"result of set_union of s1,s2"<<endl; end = std::set_union(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//并集 first = str; while(first<end) cout <<*first++<<" "; cout<<endl<<endl<<"result of set_difference of s2 relative to s1"<<endl; first = str; end = std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//s2相对于s1的差集 while(first<end) cout <<*first++<<" "; cout<<endl<<endl<<"result of set_difference of s1 relative to s2"<<endl; first = str; end = std::set_difference(s2.begin(),s2.end(),s.begin(),s.end(),str,compare());//s1相对于s2的差集 while(first<end) cout <<*first++<<" "; cout<<endl<<endl; first = str; end = std::set_symmetric_difference(s.begin(),s.end(),s2.begin(),s2.end(),str,compare());//上面两个差集的并集 while(first<end) cout <<*first++<<" "; cout<<endl; return 0; }运行结果:
三、元素的添加准则
#include <iostream> #include <set> #include <string> using namespace std; //type for sorting criterion template <class T> class RuntimeCmp { public: enum cmp_mode {normal,reverse}; private: cmp_mode mode; public: //constructor for sorting criterion //default criterion uses value normal RuntimeCmp (cmp_mode m = normal) : mode(m) { // ... } //comparsion of elements bool operator() (const T &t1, const T &t2) const { return mode == normal ? t1 < t2 : t2 < t1; } //comparsion of sorting criteria bool operator== (const RuntimeCmp &rc) { return mode == rc.mode; } }; //type of a set that uses this sorting criterion typedef set<int, RuntimeCmp<int> > IntSet; //foward declaration void fill(IntSet& iset); void print(const string name, const IntSet &iset); int main(int argc, char **argv) { //create, fill ,and print set with normal element order //uses default sorting criterion IntSet coll; fill(coll); print("coll", coll); //create sorting criterion with reverse element order RuntimeCmp<int> reverse_order(RuntimeCmp<int>::reverse); //create, fill ,and print set with reverse element order IntSet coll2(reverse_order); fill(coll2); print("coll2", coll2); //assign elements AND sorting criterion coll = coll2; coll.insert(3); print("coll", coll); //just to make sure .... if (coll.value_comp() == coll2.value_comp()) { cout<<"coll and coll2 have same sorting criterion"<<endl; } else { cout<<"coll and coll2 have different sorting criterions"<<endl; } return 0; } void print(const string name, const IntSet &iset) { cout<<name<<" : "; copy(iset.begin(), iset.end(), ostream_iterator<int>(cout, " ")); cout<<endl; } void fill(IntSet &iset) { //fill insert elements in random order iset.insert(4); iset.insert(7); iset.insert(5); iset.insert(1); iset.insert(6); iset.insert(2); iset.insert(5); }
运行结果:
在我的印象中,set就是一个元素不重复的集合,而事实上也正是这样的。无论从MSDN还是任何其它地方,都会告诉我们set的元素不可以重复。反之,只要元素不重复,就可以顺利的放入到set中。看起来这实在是再清楚不过了,但是仔细想一想的话,就会发现,话说只要不重复的元素就可以被放入到一个set中,但是什么样的元素是不重复的元素呢?或者说,什么样的元素是互不相同的呢?对于内置数据类型,也就是传说中的primary data type,像int 、 double、unsigned,甚至string,这些元素的“相同”非常容易理解,那么对于自定义类型呢?什么样的数据是相同的呢?什么样的数据又是不同的呢?
在以前学习STL的时候,曾经学到过,如果要将自定义的类型放入到set中的话,就需要重载“<”符号,原因是set是一个有序的集合,集合会按照“<”比较的大小,默认按照从小到大的顺序排列。假设我现在设计如下类型:
class MyType { public: int a, b, c; }
这是,为了让MyType类型可以顺利的放进set中,我必须重载“<”,这时问题来了,要如何重呢?载这类三个型有个数据成员,我能不能要求按排照a的大小列,如果a相等的话就随便按照b或者c的大小排列呢?如果近实现按照a的大小排列的话,重载函数如下:
bool operator< (const MyType& myType) const { return a < myType.a; }
#include <iostream> #include <set> using namespace std; class MyType { public: int a, b, c; MyType(int a, int b, int c):a(a), b(b), c(c) { } bool operator< (const MyType& myType) const { return a < myType.a; } }; int main() { set<MyType> se; MyType type1(1,2,3); MyType type2(1,2,4); se.insert(type1); se.insert(type2); cout<<"The set size:"<<se.size()<<endl; cout<<"Elements in the set as follows:"<<endl; for(set<MyType>::iterator it = se.begin(); it != se.end(); it++) { cout<<"("<<it->a<<", "<<it->b<<", "<<it->c<<") "; } cout<<endl; return 0; }
bool operator< (const MyType& myType) const { return a < myType.a ? true : (b < myType.b ? true : c < myType.c); }
#include <iostream> #include <set> using namespace std; class MyType { public: int a, b, c; MyType(int a, int b, int c):a(a), b(b), c(c) { } bool operator< (const MyType& myType) const { return a < myType.a ? true : (b < myType.b ? true : c < myType.c); } }; int main() { set<MyType> se; MyType type1(1,2,3); MyType type2(1,2,4); se.insert(type1); se.insert(type2); cout<<"The set size:"<<se.size()<<endl; cout<<"Elements in the set as follows:"<<endl; for(set<MyType>::iterator it = se.begin(); it != se.end(); it++) { cout<<"("<<it->a<<", "<<it->b<<", "<<it->c<<") "; } cout<<endl; return 0; }