变形的哈希表--位图

位图的概念
在一个结构中,用一个比特位来描述一个数据的状态,这种结构就称为位图。位图实际上是哈希表的一种变形。

1. 位图的结构定义

首先,该位图中最大能表示的比特位个数需要提前设定。
然后,根据最大比特位数来进行内存的申请。内存不能以比特位为单位进行申请,所以可以自己选用一种数据类型来申请内存,这里以64位8字节为一个数组元素长度进行内存的申请。

#pragma once
#include<stdio.h>
#include<stddef.h>
#include<stdint.h>  //uint64_t

#define MAXSIZE 1000

typedef  uint64_t BitMapType;

//位图以uint64_t为单位进行内存的申请
typedef struct BitMap
{
    uint64_t* data;
    size_t capacity; //位图中最大能表示的比特位个数
}BitMap;


//位图初始化
void BitMapInit(BitMap* bm, uint64_t capacity)
{
    if(bm==NULL)
    {   //非法输入
        return ;
    }
    bm->capacity=capacity;
    //如果位图最大表示100个数字,则需要2个64位的内存
    //如果位图最大表示200个数字,则需要4个64位的内存

    //malloc以字节为单位进行内存申请
    uint64_t size=bm->capacity/(sizeof(BitMapType)*8)+1;

    bm->data=(BitMapType*)malloc(size*sizeof(BitMapType));
    //初始化时将位图中的各个位均置为0,方便后续操作
    memset(bm->data,0,size*sizeof(BitMapType));
    return ;
}

//测试某一位是否为1
int BitMapTest(BitMap*bm, uint64_t index)
{
    if(bm==NULL||index>=bm->capacity)
    {
        //非法输入
        return 0;
    }
    uint64_t n;
    uint64_t offset;
    //获取index 所在的数组元素下标及偏移量
    GetOffset(index, &n ,&offset);

    //用1与之安位与,如果结果为0,则该位是0,否则是1
    //如果该位为1时,按位与的结果必定只有该位位1,其余位为0,所有对结果进行判断时
    //只能跟0进行比较,不能和1进行比较
    uint64_t ret=bm->data[n]&(0x1ul<<offset);
    if(ret==0)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

//将获取指定位所在的数组下标及其偏移量封装位函数
void GetOffset(uint64_t index, uint64_t* n, uint64_t* offset)
{
    //首先计算该位在那个数组元素中(数组元素64位为一个单元)
    //计算完之后的n表示,该位在下标位n的数组元素内(数组下标从0开始计数)
    *n =index/(sizeof(BitMapType)*8);

    //计算该位在 元素的哪个位上
    *offset= index % (sizeof(BitMapType)*8);
    return ;
}



//给某一位设置为1
void BitMapSet1(BitMap* bm, uint64_t index)
{
    if(bm==NULL||inddex >=bm->capacity)
    {
        //非法输入
        return ;
    }

    //计算该位所在的数组下标及其偏移量
    uint64_t n;
    uint64_t offset;
    GetOffset(index, &n ,&offset);

    //再将该位设置为1
    //但是要保证其他位不变,此时就要使其他位与0进行按位或
    //因此,该位要与1进行按位或,才能保证该位置位1,而其他位置也保持步变

    //按位操作后的结果不会改变原来的值,所以要对其进行赋值
    bm->data[n]=bm->data[n]|(0x1ul<<offset);
    return ;

}

//给某一位设置0

void BitMapSet0(BitMap* bm, uint64_t index)
{
    if(bm==NULL||index >=bm->capacity)
    {
        return ;
    }

    uint64_t n;
    uint64_t offset;
    GetOffset(index, &n, &offset);

    //根据数组元素下标和偏移量设置0
    //将该位设置为0时,保证其他位保持不变
    //所以其他位与1进行按位与(其他位可以与0进行按位或,
    //     但是index所在的位置要置为0,只能进行按位与运算)
    //~按位取反
    bm->data[n]=bm->data[n]& ~(lu1<<offset);
}

//将位图所以位都置为1
void BitMapFill(BitMap* bm)
{
    if(bm==NULL)
    {
        //非法输入
        return ;
    }
    //将位图所占的内存区域所有位置均置1
    //使用memset来进行置1,该函数是以字节为单位设置
    //所有要使一个字节的8个比特位均为1,则需要将一个字节置为0xff

    uint64_t size=bm->capacity/(sizeof(BitMapType)*8)+1;
    memset(bm->data,0xff,size*sizeof(BitMapType));
    return ;
}

//将位图所有位置都置为0
void BitMapClear(BitMap* bm)
{
    if(bm==NULL)
    {
        return ;
    }

    //将位图中的所有比特位置0
    //先计算位图共占了多少个64位的存储单元
    uint64_t size=bm->capacity/(sizeof(BitMapType)*8)+1;
    memset(bm->data,0x0,size*sizeof(BitMapType));
    return ;
}

//销毁位图
void BitMapDestroy(BitMap* bm)
{
    if(bm==NULL)
    {
        return ;
    }
    bm->capacity=0;
    free(bm->data);
    return ;
}

猜你喜欢

转载自blog.csdn.net/yu876876/article/details/81185736