哈希變形----位圖

瞭解過哈希表,我們接下來看一看哈希表的變形—–位圖。
位圖:顧名思義就是以bit位爲單位,但是需要注意的是我們的位圖並不能存儲我們的數據,而是借用這樣一個結構標記某一個數據是否存在。
如圖所示,如果該數據存在,則就將該位圖中的相應位從0置爲1。
這裏寫圖片描述
下面我們來實現一下位圖的基本操作:

//以下爲bit_map.h文件內容
#pragma once

#include<stdint.h>
#define BitmapDataType uint64_t

typedef struct Bitmap
{
    BitmapDataType *data;
    BitmapDataType capacity;//位圖最多能夠容納的個數
}Bitmap;

//初始化
void BitmapInit(Bitmap *bm,uint64_t capacity);
//銷燬
void BitmapDestroy(Bitmap *bm);
//判斷某一位是否爲1
int BitmapTest(Bitmap *bm,uint64_t index);
//設置某一位爲1
void BitmapSet(Bitmap *bm,uint64_t index);
//設置某一位爲0
void BitmapUnset(Bitmap *bm,uint64_t index);
//將位圖全部位置爲1
void BitmapFill(Bitmap *bm);
//將位圖全部位置爲0
void BitmapClear(Bitmap *bm);
//初始化
void BitmapInit(Bitmap *bm,uint64_t capacity)
{
    if(bm == NULL)
    {
        //非法輸入
        return;
    }
    //capacity:指定位圖最多能夠容納多少位
    //此處我們使用的uint64_t佔8個字節,64位
    //比如:capacity=100,應該容納2個元素纔能有足夠的位表示100位
    //比如:capacity=200,應該容納4個元素纔能有足夠的位表示200位
    //比如:capacity=300,應該容納5個元素纔能有足夠的位表示300位
    //比如:capacity=N,N/(sizeof(uint64_t)*8)+1
    bm->capacity = capacity;
    //size表示我們申請內存時對應的數組元素個數
    uint64_t size = capacity/(sizeof(uint64_t)*8)+1;
    bm->data = \
    (BitmapDataType*)malloc(sizeof(BitmapDataType)*size);
    memset(bm->data,0,sizeof(BitmapDataType)*size);
    return;
}
//測試一下
void TestInit()
{
    Test_Header;
    Bitmap bm;
    BitmapInit(&bm,100);
    printf("expected bm->capacity = 100,\
    actual bm->capacity = %lu\n",bm.capacity);
}
//銷燬
void BitmapDestroy(Bitmap *bm)
{
    if(bm == NULL)
    {
        //非法輸入
        return;
    }
    bm->capacity = 0;
    free(bm->data);
    return;
}

測試結果:
這裏寫圖片描述

//此處判斷某一位是否爲1的函數可用於後面的函數的測試

//輔助函數
void GetOffset(uint64_t index,uint64_t *n,uint64_t *offset)
{
    //n是數組中的哪一個元素
    *n = index/(sizeof(BitmapDataType)*8);
    //offset是該元素中的bit位中的哪一位
    *offset = index%(sizeof(BitmapDataType)*8);
    return;
}
//檢測某一位是否爲1,返回1表示該位爲1,返回0表示該位爲0
int BitmapTest(Bitmap *bm,uint64_t index)
{
    if(bm == NULL || index >= bm->capacity)
    {
        //非法輸入
        return 0;
    }
    uint64_t n,offset;
    //找到需要判斷的位置對應於我們數組中的哪一個元素的哪一位
    GetOffset(index,&n,&offset);
    //先將1左移offset位,結束以後相應位即爲1
    //再將其與對應的數組中的元素按位與
    //0和1與爲0,1和1與爲1
    //按位與運算完畢就可以知道相應位是否爲1
    uint64_t ret = bm->data[n] & (0x1ul << offset);
    return ret > 0 ? 1:0;
}
//將某一位設置爲1
void BitmapSet(Bitmap *bm,uint64_t index)
{
    if(bm == NULL || index >= bm->capacity)
    {
        //非法輸入
        return;
    }
    uint64_t n,offset;
    //找到需要判斷的位置對應於我們數組中的哪一個元素的哪一位
    GetOffset(index,&n,&offset);
    //將1左移offset位,移動結束以後,需要設置的位置即爲1,其餘位置爲0
    //再將其與數組中對應的元素按位或
    //0和1或是1,1和1或是1
    //有這樣的規則,按位或就不會影響其他位的狀態
    bm->data[n] |= (0x1ul << offset);
}
//將某一位設置爲0
void BitmapUnset(Bitmap *bm,uint64_t index)
{
    if(bm == NULL || index >= bm->capacity)
    {
        //非法輸入
        return;
    }
    uint64_t n,offset;
    //找到需要判斷的位置對應於我們數組中的哪一個元素的哪一位
    GetOffset(index,&n,&offset);
    //先將1左移offset位,那麼相應位變爲1其餘位爲0
    //再取反,則相應位爲0,其餘位爲1
    //在將該結果與對應的數組元素進行按位與
    //1和0與結果爲0,0和0與結果爲0(達到將某一位置爲0的效果)
    //有這樣的規則,則我們的按位與操作不會影響其他的位的狀態
    bm->data[n] &= ~(0x1ul << offset);
}
//測試一下
void TestSetAndUnset()
{
    Test_Header;
    Bitmap bm;
    BitmapInit(&bm,100);
    printf("[將位圖某一位置爲1函數測試結果]\n");
    //將第二位設置爲1
    BitmapSet(&bm,2);
    //非法測試,將第100爲設置爲1
    BitmapSet(&bm,100);
    int ret1 = BitmapTest(&bm,2);
    int ret2 = BitmapTest(&bm,100);
    printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
    printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
    printf("[將位圖某一位置爲0函數測試結果]\n");
    //將第二位設置爲0
    BitmapUnset(&bm,2);
    //非法測試,將第100位設置爲0
    BitmapUnset(&bm,100);
    int ret3 = BitmapTest(&bm,2);
    int ret4 = BitmapTest(&bm,100);
    printf("expected ret3 = 0,actual ret3 = %d\n",ret3);
    printf("expected ret4 = 0,actual ret4 = %d\n",ret4);
}

測試結果:
這裏寫圖片描述

//將位圖全部置爲1
void BitmapFill(Bitmap *bm)
{
    if(bm == NULL)
    {
        //非法輸入
        return;
    }
    uint64_t size = bm->capacity/(sizeof(BitmapDataType)*8)+1;
    memset(bm->data,0xff,sizeof(BitmapDataType)*size);
}
//將位圖全部置爲0
void BitmapClear(Bitmap *bm)
{
    if(bm == NULL)
    {
        //非法輸入
        return;
    }
    uint64_t size = bm->capacity/(sizeof(BitmapDataType)*8)+1;
    memset(bm->data,0x0,sizeof(BitmapDataType)*size);
}
//測試一下
void TestClearAndFill()
{
    Test_Header;
    Bitmap bm;
    BitmapInit(&bm,100);
    printf("[將位圖全部置爲1函數測試結果]\n");
    //將位圖全部置爲1函數測試
    BitmapFill(&bm);
    int ret1 = BitmapTest(&bm,50);
    printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
    ret1 = BitmapTest(&bm,0);
    printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
    ret1 = BitmapTest(&bm,99);
    printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
    printf("[將位圖全部置爲0函數測試結果]\n");
    //將位圖全部清0函數測試
    BitmapClear(&bm);
    int ret2 = BitmapTest(&bm,50);
    printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
    ret2 = BitmapTest(&bm,0);
    printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
    ret2 = BitmapTest(&bm,99);
    printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
}

測試結果:
這裏寫圖片描述

發佈了110 篇原創文章 · 獲贊 47 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章