位图

位图法就是用一个位来存放某个数据的存在状态。

比如:用一个20位长的内存空间可以表示一个所有元素都小于20的简单的非负整数集合。对于集合{1,2,3,5,8,13}可用如下方式表示


               0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0


这样,我们就可以用20位来表示上面集合所有元素的存在状态。


当然利用位图我们可以节省很多空间,比如素数筛选中,有一个bool数组prime,我们知道,在C语言中所有数据类型中的最小的至少也是一个字节,而一般来说,bool在C语言中是占一个字节的,也就是8位,可以看出,如果我们用一个位来表示prime数组中的数字i是否是素数,那么空间只需要原来的八分之一。


当然假设我们定义了一个int数组,而想用这个int数组的每一位来表示一个数的存在状态,那么就有两个重要的操作:设置位置为x的数据的存在状态,读取位置为x的数据存在状态。我分别来讲解这两种操作:



(一)设置位置为x的数据的存在状态


   对于这个操作,我们应该先找到x所在的位置,包括数组下标的位置和下标对应的位的位置。对于int数组来说,因为一个int占4字节,那么有32位,设SHIFT = 5,RADIX = (1 << SHIFT) - 1,用flag[]数组来表示,那么此操作就可以用如下代码来表示:

void SetBit(int x)  
{  
    flag[x>>SHIFT] |= (1<<(x&RADIX));  
}  

(二)读取位置为x的数据存在状态


   对于读操作,跟写操作差不多,也是应该先找到x所在的位,然后&一下就取出对应的位的状态了,如下:

bool GetBit(int x)  
{  
    return flag[x>>SHIFT] & (1<<(x&RADIX));  
}  

这样通过位图这种数据结构,我们可以用较少的空间来实现。


下面是用位图实现的素数筛选:

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>

using namespace std;
const int N = 100000005;
const int M = 6000005;
const int SHIFT = 5;
const int RADIX = (1 << SHIFT) - 1;

int flag[(N>>SHIFT)+1];
int p[M];
int k;

inline void SetBit(int x)
{
    flag[x>>SHIFT] |= (1<<(x&RADIX));
}

inline bool GetBit(int x)
{
    return flag[x>>SHIFT] & (1<<(x&RADIX));
}

void isprime()
{
    k = 0;
    for(int i=2; i<N; i++)
    {
        if(!GetBit(i))
        {
            p[k++] = i;
            for(int j=i+i; j<N; j+=i)
                SetBit(j);
        }
    }
}

int main()
{
    isprime();
    return 0;
}

  以上是位图的实现原理及操作。实际上在C++的STL中,有一个bitset位图容器,它所定义的数据就是占一个位,这样就方便了许多,所以利用它实现起来比较高效。用法如下:

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <bitset>

using namespace std;
const int N = 100000005;
const int M = 6000005;

bitset<N> prime;
int p[M];
int k;

void isprime()
{
    k = 0;
    prime.set();
    for(int i=2; i<N; i++)
    {
        if(prime[i])
        {
            p[k++] = i;
            for(int j=i+i; j<N; j+=i)
                prime[j] = false;
        }
    }
}

int main()
{
    isprime();
    return 0;
}



位图

上一篇:Java网络编程 入门学习笔记(一)


下一篇:解决CreateProcess()的等待时间问题