《编程珠玑》第一章提出了一个排序问题,可以用位图或位向量来表示。如可用一个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
代表集合中数字的位都置为1,其他所有的位都置为0。
若给定表示文件中整数集合的位图数据结构,则可以分三个自然阶段来编写程序。第一阶段将所有的位都置为0,从而将结合初始化为空。第二阶段读入文件中的每个整数来建立结合,将每个对应的位都置为1。第三个阶段检验每一位,如果该位为1,就输出对应的整数。伪代码如下:
/*phase 1: initialize set to empty*/
for i=[0,n)
bit[i]=0
/*phase 2: insert present elements into the set*/
for each i in the input file
bit[i]=1
/*phase 3: write sorted output*/
for i=[0,n)
if bit[i]==1
write i on the output dile
一个字符占一个字节,也就是4个位,但是我们只需要一个位来表示,这样还是会造成浪费。可以用整数数组来模拟位数组。下面是习题2的参考答案,使用位逻辑运算来实现位向量图。
// bitmap.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
#define BITSPERWORD 32 //表示一个整型含有32位
#define SHIFT 5
#define MASK 0x1F //0000000000000000 0000000000011111
#define N 10000000 //表示1000万个整数
using namespace std;
int a[1 + N / BITSPERWORD];//使用整型数组模拟1000万个位的数组
void set(int i){
//i>>SHIFT相当于i/32,表示该数由第几个整数表示,i&MASK相当于i%32,表示该数在整数中的第几个位
//1<<(i&MASK)就将该位设为1
a[i >> SHIFT] |= (1 << (i&MASK));
}
void clr(int i)
{
a[i >> SHIFT] &= ~(1 << (i&MASK));
}
int 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);
cout << "输入数据:" << endl;
while (cin >> i)
set(i);
cout << "输出结果:" << endl;
for (i = 0; i < N; ++i)
{
if (test(i))
cout << i <<" " ;
}
cout << endl;
return 0;
}
实验结果如下:
后记:
输入数据限制在相对较小的范围内,数据没有重复的情况下,可以考虑使用位图来存储数据实现排序。
参考: