位图算法(编程珠玑例题)

输入:一个最多包含n个正整数的文件,最大不超过一千万,每个数最多只出现一次,数据之间没有明显的关联

输出:升序排列的整数列表

要求:只有大约1MB的内存可用,磁盘空间充足,运行时间最多不超过1分钟,10秒左右就可以不需要优化

 

分析:1MB的内存只能存储大约250000个int型整数,远远低于1千万的要求,但是每个int型整数有32位,如果用第i位的0,1来表示数据i的存在与否,一千万的整数需要1000 0000/32=312500个整数,他们将占有312500*4=1250000个比特,即大约1.2MB的内存。

 

但如果要求内存上限是1MB的话,可以使用两趟来实现,一次一半,使用5000000/8=625000个字节的空间进行从0~4999999的排序,(通过控制仅仅读入范围在0到4999999的数字,其他的忽略掉)之后把结果存储在磁盘中,然后再排序5000000~9999999的整数,把结果跟刚才的结果组合起来即可。

 

 

 

其中SHIFT=log(32)=5, i>>SHIFT=i/32(25=32),在整个a数组中,每个元素都可以代表32个整数的存在,所以在一千万个数中我们应该先确定数字i在那个数组中,很明显他应该位于i/32的位置,即a[i>>SHIFT]

 

当我们想对一个int整数的第x位置1的操作的时候:

int bitrow=0;

bitrow |=1<<(x);

以上代码可以做到,在我们的i中,i=32*n+x,这个x将决定i值在对应的数组元素中哪个位置,所以对i进行模运算可以解决,则set(int i)实现方式为:

a[i/32] |= 1<<(i%32)   等价于 a[i>>SHIFT] |=1<<(i&MASK)

 

总结:

a%BITSPERROW==a&(BITSPERROW-1)==a&MASK

a/BITSPERROW==a>>log(BITSPERROW)==a&SHIFT 

 

另外一个类似的问题:

 

Question:给40亿个不重复的无序整数集合,要求判断一个数是否属于这个集合?

Ans:以上解法给出O(1)复杂度的解决方案,但是需要注意40亿个数占用约480MB的内存,可以考虑分次使用多趟算法来实现,方法上面已经叙述过了,K趟算法可以在Kn的时间开销和n/k的空间开销内完成最多n个小于n的无重复整数排序。

 

 

位图排序其实是一种HASH映射,把对应的正整数映射到位图集合中,每一个bit代表一个整数的存在与否,这种方法可以应用在海量规模数据的快速查找,时间复杂度O(1),但空间复杂度稍高,需要注意的这种方式要求数据最好不要有重复,否则实现起来会比较麻烦,

下面给出数据有重复的思路,假设数据至多重复10次:

 

对于无重复的case来说,一个数据位就可以表示有无,可以理解为重复度为1,但是如果重复度超过1,则一个数据位就无法表达,根据2进制数据位来说,若想表达10的重复度,至少需要4个数据位,也就是说,把前一个case做了适当的推广,由一个bit推广到4个bits就可以解决问题。

 

 

 

set_add的操作其实不难理解,由于要计算重复度,所以由上面的“置位”操作改为“加一”操作,我们需要用4个bit位来表示一个整数出现的次数。我们把4个bit当成“一个bit”来看,这样的话还是“一个bit”表示一个整数,那么一个int型数组元素就有8个这样的“比特”,延续上面的思路,我们首先要定位它会出现在哪个int数组元素中:

int label=i<<3 , 3=log8

之后再确定它会对应该元素中的哪一个“bit”(一共有8个):

int pos=4*(i&MASK),乘以4是因为对于每一个i的增长,我们希望对应在a[]中已定位到的元素中4个比特位的跳跃——4个比特位被我们看成“一个比特”,以防止数据存储相互冲突

之后取出这个“bit”,每次加一,然后再重新写入原来的对应位中。

关于重复度的思路来自:http://blog.csdn.net/clearriver/archive/2009/07/19/4361941.aspx

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值