Programming Pearls 笔记(1)(续)

     对于我上次提到的问题:怎么开107这么大的数组?这个问题可能是比较弱智的。。。。鄙视自己。。。

     之所以要开107这么大的数组,如果是int a[107],则我们就是用一个int 存储一个信息。这就是大量浪费。而我们知道一个int 有四个字节,在一般的机器上都是32位,即一个int可以表示32个0和1。所以我们数组就可以开成a[1+107/32],这样数组不就小了?

     刚好COLUMN1的习题二就是要求实现这个问题:How would you implement bit vectors usingbitwise logical operations(such as and,or and shift)?

     我在官网找到代码如下,并做了简要分析:

/* Copyright (C) 1999 Lucent Technologies */
/* From 'Programming Pearls' by Jon Bentley */

/* bitsort.c -- bitmap sort from Column 1
* Sort distinct integers in the range [0..N-1]
*/

#include <stdio.h>

#define BITSPERWORD 32//int应该有四个字节,即可以表示32个 0与1
#define SHIFT 5//左移5位即为除以32
#define MASK 0x1F//31的十六进制表示
#define N 10000000//题目要求10^7的大小
int a[1 + N/BITSPERWORD];//10000000/32,马上把a[10000000]的大小降下来了。
//i>>SHIFT表示左移五位,“|=”就是a|=b即a=a|b,不用多说。关键是i&MASK等同于i%32,这个结论我会在后面解释。
void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK)); }//在相应的位置上置1
void clr(int i) { a[i>>SHIFT] &= ~(1<<(i & MASK)); }//置0
int test(int i){ return a[i>>SHIFT] & (1<<(i & MASK)); }//取出相应位置上的值

int main()
{ int i;
for (i = 0; i < N; i++)
clr(i);//初始化
/*
Replace above 2 lines with below 3 for word-parallel init
int top = 1 + N/BITSPERWORD;
for (i = 0; i < top; i++)//另一种初始化,没什么说的
a[i] = 0;
*/
while (scanf("%d", &i) != EOF)
set(i);//对数据的读入
for (i = 0; i < N; i++)
if (test(i))
printf("%d\n", i);//如果在数组里存在i,就输出,明显是从小到大输出的
return 0;
}
//有个结论:m%n,当n为2的x次幕的时候,取余可表示为m&(n-1)
//分析完这段代码,只想说一句话:神一般的存在啊!!

      刚开始,乍一看这个代码,顿时就懵了。。。。。。完全不知所云。后经查证,慢慢看懂了。关键部分其实就是这样

      

1 void set(int i) {        a[i/32] |=  (1<<(i % 32)); }
2 void clr(int i) { a[i/32] &= ~(1<<(i % 32)); }
3 int test(int i){ return a[i/32] & (1<<(i % 32)); }

      然后我这里证明下那个结论,应该是说明下:

      显然我们知道 : 21=10

                            22=100

                            23=1000(即2的N次幂,就是1后面n个0)

      然后对于任意的m,我们改写成二进制形式,例如:m=1010110,可以写成m=1010000+110。

      记a=1010000,b=110。则m%n=(a+b)%n=a%n+b%n。

      设n=22=100,显然,a%n=0。而b%n ,此时b与n的位数相同,n=(1后面几个零的形式),所以b&(n-1)应该就是余数  即  110%100=10     110&011=10。

      即 1010110%100=10,1010110&0000011=0000010。

      基本上就是这样了,不知道说没说清楚。这也算不上是证明。

      

 

      分析完这段代码,如果不是对底层汇编比较熟悉的话,是不可能写出来这样的代码的。理论上,移位操作是可以实现任何运算,且效率应该都是较高的。这个bitmap的思想是很好的。



转载于:https://www.cnblogs.com/xibaohe/archive/2012/02/27/2367380.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值