位向量實現集合—王曉東數據結構


王曉東數據結構中集合一章,用位向量實現集合看的很懵記錄一下。

N是一個不大的固定整數時,{1,2...N}是N的子集 假如N=10000,可以用數組A[N]來表示這個集合的存在,此時數組大小為A[N],如A[1]=1表示集合中第一個元素存在。

位向量顧名思義就是用位來存儲元素。以書中unsigned short類型為例,下面用US表示。US占位2個字節,16位,那么一個US就可以表示16個數,那么這N個數只需要用N/16 個US類型數表示。此時A數組大小為A[N/16+1],

A[0]表示1-16個數(0-15)

A[1]表示2-32個數(16-31)

...

A[0]=13,可看成000000001011,A[0]的第一個位置、第二個位置、第四個位置的數存在,即0、1、3三個數存在。 

假如輸入一個數30,首先先確定在數組哪個位置,30/16=1,此時應在數組A[1]里,計算在A[1]中的位置則只需要30%16+1=15,表示在第15個位置。

下面解析王曉東書中集合的實現方法:

集合的基本運算:

//並集運算:其運算結果為集合A和集合B的並集
Set SetUnion(Set A,Set B);

//交集運算:其運算結果為集合A和集合B的交集
Set SetIntersection(Set A,Set B);

//賦值運算:將集合B賦值給A
void SetAssign(Set A,Set B);

//判斷運算:相等返回1 否則返回0
int SetEqual(Set A,Set B);

//成員運算:x與集合相同的類型,當x屬於S時,返回1 否則返回0
int SetMember(int x,Set set);

//插入運算:將x與插入集合S,當x本身屬於S時,不改變集合
void SetInsert(int x,Set s);

//刪除運算:將集合S中的x元素刪除,當x不屬於S時,不改變集合
void SetDelete(int x,Set s );

Set集合定義:

typedef struct set
{
    int size;//能存儲元素規模
    //數組大小應該看類型 如v為 ushort應該一個數可以存16個 大小為arr/16+1||(size+15)
    int arraysize;
    //向量組 每個向量能存儲16個
    unsigned short *v;
} Bitset, *Set;

SetInit函數用於創建新Set:

Set InitSet(int size)
{
    Set _set = new Bitset;
    _set->size = size;
    //一個US類型可以表示16個 故數組大小為1+size/16
    //書中這種向右移動4位的運算方式等同於/16
    _set->arraysize = (size+15)>>4;
    //書中v大小為size 個人認為有錯,有不同意見的朋友歡迎探討
    _set->v = new unsigned short[_set->arraysize];
    for (int i = 0; i <_set->arraysize; i++) 
{
_set
->v[i] = 0;
}
return _set;
}

SetAssign函數用於賦值:

//把B賦值給A
void SetAsign(Set A, Set B)
{
    if (A->size != B->size)
        return;
    for (int i = 0; i < A->size; i++)
    {
        A->v [i] = B->v[i];
    }
}

ArrayIndex尋找數在數組中的位置:

//計算位置大小 除類型的大小 UShort為16 故要/16 按位的話/4即可
int ArrayIndex(int x){
    return x>>4;
}

BitMask函數尋找在US位置中第幾位:

//計算這個數在一個ushort里面所在的第幾個位置 除16取余+1即可
//輸入10二進制為1010為15 1111 &計算得1010表示10 之后右移
unsigned short BitMask(int x){
    return 1<<(x&15);
}

SetInsert插入函數:

//位插入運算 查找數組位置  找到x%16放置 用|運算
//如17插入,此時數組v[1]中為00100000,表示第七個位置有東西,17%16+1=2 |運算后v[1]為00100010
void SetInsert(int x,Set s){
    if(x<0||s->size<x)
        return;
    s->v[ArrayIndex(x)]|=BitMask(x);
}

SetDelete刪除函數:

//刪除元素運算 先取反再去取&
//如刪除17,此時數組v[1]中為00100010,表示第2、7個位置有東西,17%16+1=2 ~2取反為11111101 &運算后v[1]為00100000
void SetDelete(int x,Set s ){
     if(x<0||s->size<x)
        return;
     s->v[ArrayIndex(x)]&=~BitMask(x);
}

SetMember函數查看元素是否存在:

//檢測元素是否存在
int SetMember(int x,Set set){
    if(x<0||x>set->size)
        return 0;
    //首先查找數組對應位置,與x相對的位置
    //如3 此時在數組第一個位置 BitMask值為1000 表示第4數,第1個為0
    return set->v[ArrayIndex(x)]&BitMask(x);
}

SetEqual函數判斷集合A和B是否相等:

int SetEqual(Set A,Set B){
    if(A->size! B->size)
        return 0;
    for (int i = 0; i < A->arraysize; i++)
    {
        if(A->v[i]! B->v[i])
            return 0;
    }
    return 1;
}

SetUnion並集運算:

//取並集  如A=1100 B=0110 此時第2、3、4個為並集
Set SetUnion(Set A,Set B){
    Set s=InitSet(A->size);
    for (int i = 0; i < s->arraysize; i++)
    {
        //按位|
        s->v[i]=A->v[i] B->v[i];
    }
}

SetIntersection交集運算:

//取交集  如A=1100 B=0100=>0100 此時第3個為交集
Set SetIntersection(Set A,Set B){
    Set s=InitSet(A->size);
    for (int i = 0; i < s->arraysize; i++)
    {
        //按位&
        s->v[i]=A->v[i] B->v[i];
    }
}

SetDifference差集運算:

//取差集  如A=111000 B=001000=>取&為001000 再異或110000 此時第5.6個為差集
Set SetDifference(Set A,Set B){
    Set s=InitSet(A->size);
    for (int i = 0; i < s->arraysize; i++)
    {
        //按位& 再^
        s->v[i]=A->v[i]^(A->v[i]&B->v[i]);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM