zoukankan      html  css  js  c++  java
  • 数据结构-集合

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

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

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

    集合的抽象数据类型:

    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;
    }
  • 相关阅读:
    四则运算2
    大二第二学期阅读计划
    第一周课堂练习
    《人月神话》读后感
    软件工程概论总结第十一章
    软件工程概论总结第十章
    软件工程概论总结第九章
    软件工程概论总结第八章
    软件工程概论总结第七章
    第五章、软件过程中的形式化方法
  • 原文地址:https://www.cnblogs.com/yangyuliufeng/p/9480034.html
Copyright © 2011-2022 走看看