集合的成员是无序的,没有先后次序关系。
每个元素在集合中只出现一次,但在实际应用中却有元素重复出现的情况。
在某些集合中保存的是实际数据值,在某些集合中保存的是表示元素是否在集合中的指示信息。
集合的抽象数据类型:
template <class T> class Set{ public: virtual Set()=0; virtual makeEmpty()=0; virtual bool addMember(const T x)=0; virtual bool delMember(const T x)=0; virtual Set<T>& intersectWith(const Set<T>& R)=0; //集合交集运算 virtual Set<T>& unionWith(const Set<T>& R)=0; //集合并集运算 virtual Set<T>& differenceFrom(const Set<T>& R)=0; //集合的差运算 virtual bool Contains(const T x)=0; //集合是否包含某个元素 virtual bool subSet(const Set<T>& R)=0; virtual bool operator==(const Set<T>& R)=0; }
1.使用位向量表示集合
用二进位数组(bit vector)来实现集合,数组采用16位无符号短整数unsigned short实现位映射,集合元素x的范围是0~setSize,数组大小vectorSize=(setSize+15)>>4。
二进制数组(也称位向量)实际上是一个指示信息数组。
求并集将位向量按位或,求交集将位向量按位与,求差集将第一个位向量和第二个位向量的反按位与
当计算某个元素是否在集合中时,需要计算ad=x/16、id=x%16以取出相应位(bitVector[ad]>>(15-id))%2
将值v(0或1)送入集合中时可以这么操作:
(1)找到元素对应位所在数组位置elem=bitVector[ad]
(1)右移,把元素对应位移动到最右,temp=elem>>(15-id)
(2)把元素左边的位保存下来elem=elem<<(id+1)
(4)根据v的值修改该元素对应位
如果该位为偶数(temp%2==0),并且v==1,则temp=temp+1
如果该位为奇数(temp%2==1),并且v==0,则temp=temp-1
(5)最后按位或得到bitVector[ad]=(temp<<(15-id))|(elem>>(id+1))
#include <iostream> #include <assert.h> using namespace std; const int DefaultSize=50; template <class T> class bitSet{ public: bitSet(int sz=DefaultSize); bitSet(const bitSet<T>& R); ~bitSet(){delete []bitVector;} void makeEmpty(){ for(int i=0;i<vectorSize;i++) bitVector[i]=0; } unsigned short getMember(const T x); void putMember(const T x,unsigned short v); bool addMember(const T x); bool delMember(const T x); bitSet<T>& operator=(const bitSet<T>& R); bitSet<T>& operator+(const bitSet<T>& R); bitSet<T>& operator*(const bitSet<T>& R); bitSet<T>& operator-(const bitSet<T>& R); bool Contains(const T x); bool subSet(bitSet<T>& R); bool operator==(bitSet<T>& R); friend istream& operator>>(istream& in,bitSet<T>& R); friend ostream& operator<<(ostream& in,bitSet<T>& R); private: int setSize; int vectorSize; //位数组大小 unsigned short *bitVector; }; template <class T> bitSet<T>::bitSet(int sz):setSize(sz){ assert(setSize>0); vectorSize=(setSize+15)>>4; //存储数组的大小 bitVector=new unsigned short[vectorSize]; assert(bitVector!=NULL); for(int i=0;i<vectorSize;i++) bitVector[i]=0; } template <class T> bitSet<T>::bitSet(const bitSet<T>& R) { setSize=R.setSize; vectorSize=R.vectorSize; bitVector=new unsigned short[vectorSize]; assert(bitVector!=NULL); for(int i=0;i<vectorSize;i++) bitVector[i]=R.bitVector[i]; } template <class T> unsigned short bitSet<T>::getMember(const T x) { //读取集合元素x,x从0开始 int ad=x/16; int id=x%16; //计算数组元素下标 unsigned short elem=bitVector[ad]; return((elem>>(15-id))%2); } template <class T> void bitSet<T>::putMember(const T x, unsigned short v) { //将值v送入集合元素x int ad=x/16; int id=x%16; unsigned short elem=bitVector[ad]; unsigned short temp=elem>>(15-id); elem=elem<<(id+1); if(temp%2==0 && v==1) temp=temp+1; //根据v的值修改该位 else if(temp%2==1 && v==0) temp=temp-1; bitVector[ad]=(temp<<(15-id))|(elem>>(id+1)); //按位或 } template <class T> bool bitSet<T>::addMember(const T x) { assert(x>=0 && x<setSize); if(getMember(x)==0) { //x所在位原为0,x不在集合中,在相应位置置1 putMember(x,1); return true; } return false; } template <class T> bool bitSet<T>::delMember(const T x) { assert(x>=0&x<setSize); if(getMember(x)==1){ putMember(x,0); return true; } return false; } template <class T> bitSet<T>& bitSet<T>::operator+(const bitSet<T> &R) { //求并集 assert(vectorSize==R.vectorSize); //判断两集合大小是否相等 bitSet temp(vectorSize); for(int i=0;i<vectorSize;i++){ temp.bitVector[i]=bitVector[i]|R.bitVector[i]; } return temp; } template <class T> bitSet<T>& bitSet<T>::operator*(const bitSet<T> &R) { //求交集 assert(vectorSize==R.vectorSize); //判断两集合大小是否相等 bitSet temp(vectorSize); for(int i=0;i<vectorSize;i++){ temp.bitVector[i]=bitVector[i]&R.bitVector[i]; } return temp; } template <class T> bitSet<T>& bitSet<T>::operator-(const bitSet<T> &R) { assert(vectorSize==R.vectorSize); //判断两集合大小是否相等 bitSet temp(vectorSize); for(int i=0;i<vectorSize;i++){ temp.bitVector[i]=bitVector[i]&!R.bitVector[i]; //用第一个集合和第二个集合的反做交运算 } return temp; } template <class T> bool bitSet<T>::Contains(const T x) { assert(x>=0 && x<=setSize); return (getMember(x)==1); } template <class T> bool bitSet<T>::subSet(bitSet<T> &R) { assert(setSize==R.setSize); for(int i=0;i<vectorSize;i++) if(bitVector[i]&!R.bitVector[i]) return false; return true; } template <class T> bool bitSet<T>::operator==(bitSet<T> &R) { if(vectorSize!=R.vectorSize) return false; for(int i=0;i<vectorSize;i++) if(bitVector[i]!=R.bitVector[i]) return false; return true; }
2.使用有序链表表示集合
用有指向附加头结点的表头指针、表尾指针的有序链表表示无穷全集合的子集
链表中的每个结点表示集合的一个成员,各个结点表示的成员升序排列
template <class T> struct SetNode{ T data; SetNode<T> *link; SetNode():link(NULL){}; SetNode(const T& x,SetNode<T> *next=NULL):data(x),link(next){}; }; template <class T> class LinkedSet{ private: SetNode<T> *first,*last; //有表头指针指向附加头结点、表尾指针 public: LinkedSet(){first=last=new SetNode<T>;}; //空有序链表,表尾指针也指向附加头结点 LinkedSet(LinkedSet<T>& R); ~LinkedSet(){makeEmpty(); delete first;} void makeEmpty(); void addMember(const T& x); bool delMember(const T& x); LinkedSet<T>& operator=(LinkedSet<T>& R); LinkedSet<T>& operator+(LinkedSet<T>& R); LinkedSet<T>& operator*(LinkedSet<T>& R); LinkedSet<T>& operator-(LinkedSet<T>& R); bool Contains(const T x); bool operator==(LinkedSet<T>& R); bool Min(T& x); bool Max(T& x); bool subSet(bitset<T>& R); }; template <class T> LinkedSet<T>::LinkedSet(LinkedSet<T>& R){ SetNode<T> *srcptr=R.first->link; first=last=new SetNode<T>; while(srcptr!=NULL){ last->link=new SetNode<T>(srcptr->data); last=last->link; srcptr=srcptr->link; } last->link=NULL; //这句话其实是多余的,因为new SetNode<T>(srcptr->data)创建结点时就默认了link为NULL } template <class T> bool LinkedSet<T>::Contains(const T& x){ SetNode<T> *temp=first->link; while(temp!=NULL && temp->data<x) temp=temp->link; if(temp!=NULL && temp->data==x) return true; else return false; } template <class T> bool LinkedSet<T>::addMember(const T& x){ SetNode<T> *p=first->link,*pre=first; //pre是扫描指针p的前驱,记录p的前驱结点地址 while (p!=NULL && p->data<x){ pre=p; p=p->link; } if(p!=NULL && p->data==x) return false; //集合中已有此元素 SetNode<T> *s=new SetNode(x); s->link=p; pre->link=s; if(p==NULL) last=s; return true; } template <class T> bool LinkedSet<T>::delMember(const T& x){ SetNode<T> *p=first->link,*pre=first; while(p!=NULL&&p->data<x){ pre=p; p=p->link; } if(p!=NULL&&p->data==x){ pre->link=p->link; if(p==last) last=pre; delete p; return true; } else return false; } template <class T> LinkedSet<T>& LinkedSet<T>::operator=(LinkedSet<T>& R){ SetNode<T> *pb=R.first->link; SetNode<T> *pa=first=new SetNode<T>; while(pb!=NULL){ pa->link=new SetNode<T>(pb->data); pa=pa->link; pb=pb->link; } pa->link=NULL; last=pa; return *this; } template <class T> LinkedSet<T>& LinkedSet<T>::operator+(LinkedSet<T>& R){ //求并集 SetNode<T> *pb=R.first->link; SetNode<T> *pa=first->link; LinkedSet<T> temp; SetNode<T> *p,*pc=temp.first; while(pa!=NULL&&pb!=NULL){ if(pa->data==pb->data){ pc->link=new SetNode<T>(pa->data); pa=->pa->link; pb=pb->link; } else if(pa->data<pb->data){ pc->link=new SetNode<T>(pa->data); pa=pa->link; } else{ pc->link=new SetNode<T>(pb->data); pb=pb->link; } pc=pc->link; } if(pa!=NULL) p=pa; //this集合未扫完 else p=pb; while(p!=NULL){ pc->link=new SetNode<T>(p->data); pc=pc->link; p=p->link; } pc->link=NULL; temp.last=pc; return temp; } template <class T> LinkedSet<T>& LinkedSet<T>::operator*(LinkedSet<T>& R){ //求交集 SetNode<T> *pa=first->link; SetNode<T> *pb=R.first->link; LinkedSet<T> temp; SetNode<T> *pc=temp.first; while(pa!=NULL&&pb!=NULL){ if(pa->data==pb->data){ pc->link=new SetNode<T>(pa->data); pc=pc->link; pa=pa->link; pb=pb->link; } else if(pa->data<pb->data) pa=pa->link; else pb=pb->link; } pc->link=NULL; temp.last=pc; return temp; } template <class T> LinkedSet<T>& LinkedSet<T>::operator-(LinkedSet<T>& R){ SetNode<T> *pb=R.first->link; SetNode<T> *pa=first->link; LinkedSet<T> temp; SetNode<T> *pc=temp.first; while(pa!=NULL&&pb!=NULL){ if(pa->data==pa->data){ pa=pa->link; pb=pb->link; } else if(pa->data<pb->data){ pc->link=new SetNode<T>(pa->data); pc=pc->link; pa=pa->link; } else pb=pb->link; } while(pa!=NULL){ pc->link=new SetNode<T>(pa->data); pc=pc->link; pa=pa->link; } pc->link=NULL; temp.last=pc; return temp; } template <class T> bool LinkedSet<T>::operator==(LinkedSet<T>& R){ SetNode<T> *pb=R.first->link; SetNode<T> *pa=first->link; while(pa!=NULL && &pb!=NULL) if(pa->data==pb->data){ pa=pa->link; pb=pb->link; } else return false; if(pa!=NULL||pb!=NULL) return false; //链不等长 return true; }