// 编程珠玑第一章习题2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N/BITSPERWORD];
void set(int i)
{
a[i>>SHIFT]^=(1<<(i&MASK));//a[i>>SHIFT] 找到a中的位置
}
void clr(int i)
{
a[i>>SHIFT]&=~(1<<(i&MASK));//1<<(i&MASK) 取得低五位,做移动1移动1<<(i&MASK)位
}
bool test(int i)
{
return a[i>>SHIFT]&(1<<(i&MASK));
}
int _tmain(int argc, _TCHAR* argv[])
{
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);
system("pause");
return 0;
}
习题9
首先,我们需要明确问题是什么。
在这里,我们有一个稀疏的数组需要访问,并且在第一次访问的时候将其初始化为0. 因为数组很大,并且需要访问的数组元素很稀疏,而程序要求的时间很宝贵。
所以,我们不能直接将data数组的各个元素都初始化为0.
我们需要做的是在第一次数组data中的某个元素的时候,将其初始化为0. 如果之后再次访问到该元素,应该能够判断其是否已经被初始化过,避免多次初始化从而覆盖数据。
在提供的解决方案中,就使用了from,to两个向量和top变量来保存哪些变量已经被初始化了。
当我们访问索引为i的data元素时,我们通过判断form[i]是否小于top,并且to[from[i]]是否等于i来判断元素树否被初始化过。
需要注意的是我们使用to向量的原因是为了防止from中的未经初始化的数据刚好因为小于top而导致出现错误判断。也就是说,我们是不对from和to向量进行初始化的(因为我们连对data进行初始化的成本都不肯),所以无法判断from中的数据哪些是我们写入的,哪些是原来就有的。于是,我们就通过增加一个to数组,并且增加一个判断条件来保证我们的判断是正确的。
当然,这样的保证也并不是绝对正确的。只是小概率事件,直接忽略了吧???
综上:
我们在访问data中索引为i的元素时,通过条件from[i]<top和to[from[i]]=i来判断该数据是否被初始化过。
如果已被初始化过,就直接访问该数据;
否则,使用如下的语句对其进行初始化,并且在from,to和top中保存该数据已被初始化过这个信息:
from[i]=top;
to[top]=i
data[i] = 0
top++.