数据结构-集合

集合的成员是无序的,没有先后次序关系。

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

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

集合的抽象数据类型:

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

将值v0或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;
}

 

posted @ 2018-08-15 10:39  扬羽流风  阅读(835)  评论(0编辑  收藏  举报