位图算法是一种使用二进制位来表示一个数是否存在的算法。
-
一个字节是八位二进制,可以表示两种状态,1和0。1表示存在,0表示不存在。
-
四个字节是32位二进制,可以表示32种状态。
-
八个字节是64位二进制,可以表示64种状态。
比如这道题:
给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】
这是一道腾讯的编程题,看起来也是难难的。如果你想要把这40亿个数存起来,那得需要多少内存?1024*1024*1024*40=4G多的内存。但是如果用位图的思想来做的话,在这里它也只是要求判断一个数在不在这些数中一个字节可以表示8位,4/8=0.5G的内存就可以表示这40个亿整数。
#pragma once
#include<iostream>
#include<vector>
using namespace std;
class BitMap
{
public:
size_t Resize(const size_t size);
void Set(size_t x);
void Reset(size_t x);
bool Test(size_t x);
protected:
vector<size_t> _map;
size_t _size;
};
#define _CRT_SECURE_NO_WARNINGS 1
#include"Bit_Map.h"
#include"commond1.h"
size_t BitMap::Resize(const size_t size)
{
size_t newsize = _GetNextPrime(size);
_map.resize(newsize);
return newsize;
}
void BitMap::Set(size_t x)
{
size_t index = x >> 6;//x/32。在顺序表的哪个下标处
while (_map.size() <=index)
Resize(_map.size());
size_t tmp = 1 << (32 - (x % 32));//找到要修改的位
if (_map[index] & tmp)
{
return;
}
_map[index] = _map[index] | tmp;
_size++;
}
void BitMap::Reset(size_t x)
{
size_t index = x >> 6;//x/32
size_t tmp = 1 << (32 - (x % 32));
if (_map[index] | tmp)
{
_map[index] = _map[index] & (~tmp);
_size--;
}
}
bool BitMap::Test(size_t x)
{
size_t index = x >> 6;
if (_map[index] & (1 << (32 - (x % 32))))
return true;
else
return false;
}
commond1.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<assert.h>
//公有的全局函数要放在一个头文件中,不能放在.cpp中,会有重定义链接错误
size_t _GetNextPrime(size_t size)
{
const int _PrimeSize = 28;
static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
for (int i = 0; i < _PrimeSize; ++i)
{
if (_PrimeList[i] > size)
return _PrimeList[i];
}
return 4294967291ul;
}
我们要表示这40个亿的数,我们就开能表示40个亿数的空间。将要找的数通过x除以32(4个字节)来找到它是在第几个size_t内,然后加上它的余数x%32就可以找到它的最终位置。将那个位置置为1就表示这个数存在。