数据结构-集合

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

数据结构-集合
集合的成员是⽆序的,没有先后次序关系。

每个元素在集合中只出现⼀次,但在实际应⽤中却有元素重复出现的情况。

在某些集合中保存的是实际数据值,在某些集合中保存的是表⽰元素是否在集合中的指⽰信息。

集合的抽象数据类型:
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;
st=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;
st=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;
st=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;
}。

相关文档
最新文档