哈希表的变形-位图(面试题)

笔试题:
给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。 【腾讯】

这可以说是一个简单的大数据问题。如果我们使用平常的办法,那么我们至少用 40亿*4/1024 *1024 =
16G内存。通常我们所使用的计算机内存为4G,16G内存计算机的价格。。。。一定会非常高吧==。
也许你会提出我们可以使用分块处理的思路,16G的硬盘我们可以提供。但是硬盘读取的速度实在有点慢了了,我们就不能快速的判断了。这里我们就可以使用位图。

位图的思想是用一个位来表示一个数,那么我们需要40亿 / 1024 * 1024 * 32 大约
500M左右的空间,这样我们的内存还是负担得起,我们用1,0来表示这个数是存在还是不存在。

假设我们需要表示的最大数字为num, 那么我们需要num个位,我们用int数组来储存(你也可以用char)那么需要num/32+1个int。

有2个问题:读取数据,如何修改相应的位?删除数据又如何修改?又如何知道它存在那?

我们读取了一个数据va,第一步需要找到储存它的位,按照我们储存它的方式,可以的出pos = va / 32, index = va
%32,pos,index表示va 应该储存在int数组第pos个数的第index位。

第二步:既然已经找到了这个位,我们需要修改这个位的状态把它设定为1,我们可以用位操作,比如把1<< index |
va就可以把va的index位设置为1。那么修改同理,我们可以用(~(1<< index)) & va把va的index位设置为0.

那么判断这个数是否存在,也就是看这位是否为1,我们可以用(1<< index)&va来判断va 的index位是否为1.

代码实现(数据结构)
BitMap

#pragma once
#include<stdio.h>
#include<assert.h>
typedef struct BitMap
{
    size_t *_bits;
    size_t _range;
}BitMap;
void InitBitMap(BitMap*bm, size_t range);//初始化
void BitMapSet(BitMap*bm, size_t x);//插入
void BitMapFind(BitMap*bm, size_t x);//查找
int BitMapTest(BitMap*bm, size_t x);//判断是否存在
void BitMapReset(BitMap* bm, size_t x);//删除

Bitmap.c

#include"BitMap.h"
void InitBitMap(BitMap*bm, size_t range)
{
    assert(bm);
    bm->_range = range;
    bm->_bits = (size_t*)malloc(sizeof(size_t)*(bm->_range/32+1));
    assert(bm->_bits);
    memset(bm->_bits, 0, sizeof(size_t)*(bm->_range / 32+1));
}
void BitMapSet(BitMap*bm, size_t x)//左移给高位移,友移给低位移
{
    assert(bm);
    size_t index = x >> 5;//算出它的位置,相当于除以32
    size_t value = x % 32;//算出它映射的具体位置

    bm->_bits[index]|= (1 << value);//将它所在的位置为1;//000000100000000
}
void BitMapFind(BitMap*bm, size_t x)
{
    assert(bm);
    size_t index = x >> 5;
    size_t value = x% 32;
    bm->_bits[index] = bm->_bits[index] & (1 << value);//0与任何数都是0;00001000 & 000010000  1
}
void BitMapReset(BitMap* bm, size_t x)
{
    size_t index = x >> 5;
    size_t value = x % 32;
    bm->_bits[index] = bm->_bits[index] & (~(1 << value));//11110111 &   00001000  0
}
int BitMapTest(BitMap*bm,size_t x)//测试这个位置的数是否存在
{
    size_t index = x >> 5;
    size_t value = x % 32;

    if ((1<<value)&(bm->_bits[index]))//如果这个位有数则为1,
        return 0;
    return -1;
}

test.c

#include"BitMap.h"
void test()
{
    BitMap bm;
    InitBitMap(&bm, -1);
    BitMapSet(&bm, 10000);


    BitMapSet(&bm, 231000);
    BitMapSet(&bm, 12300);
    BitMapSet(&bm, 320000);
    BitMapSet(&bm,10000);

    printf("%d\n", BitMapTest(&bm, -1));
    printf("%d\n", BitMapTest(&bm, 121000));
    printf("%d\n", BitMapTest(&bm, 12300));
    printf("%d\n", BitMapTest(&bm, 342000));
    printf("%d\n", BitMapTest(&bm, 2300));

}
int main()
{
    test();
    system("pause");
    return 0;
}

位图的代码实现较为简单,重在理解这个过程。它是哈希表的一个变形应用,想了解哈希表的去下面这个地址:
http://blog.csdn.net/adzn1/article/details/79462761
哈希表参考函数:
http://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值