位图在随机数的排序中用途广泛,并且耗时较少,最常用的是一位位图,即用一个bit的0/1来表示一个数,如果这个数存在就把响应的bit位置为1,否则就是0。在真正使用的时候,首先遍历数列,把表示每个数的相应bit位置1,第二次遍历位图,判断相应bit位对应数字是否存在,存在就打印输出,这样的序列自动有序。
但是单bit位有一个缺点就是,可以检测元素是否存在,但是对于含有重复元素的序列排序就无能为力了。
题目:在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数
这道题用2-bitmap可以很容易解决,每一个数用2-bit来表示,共可以表示4种状态,00表示不存在,01表示出现一次,10表示出现2次或者多次,11没有定义
2-bitmap的构造也是借助于1-bitmap,首先看一下1-bitmap的构造
#define mas 31 int a[1000000]; // 第0位表示数字0,第1位表示1 int test(int i) { return a[i>>5] & (1<<(mas - i & mas)); } void set(int i) { a[i>>5] |= 1<<(mas - i & mas); } void clear(int i) { a[i>>5] &= ~(1<<(mas - i & mas)); }
2-bitmap的构造
int getT(int i) { if(!test(i) && !test(i+1)) /* 检查表示数字的两位数字 */ return 0; else if(!test(i) && test(i+1)) return 1; else if(test(i) && !test(i+1)) return 2; else return 3; } void setT(int i) { /* 检测对应位的当前值,然后进行变换 */ int t = getT(i); switch(t) { case 0: set(i+1);break; case 1: set(i);clear(i+1);break; case 2: break; } } /* 清除当前值 */ void clearT(int i) { clear(i); clear(i+1); }
从一系列数中找出不重复元素
int main() { int n; int b[100000]; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&b[i]); memset(a,0,sizeof(a)); for(int i=0;i<n;i++) setT(b[i] * 2); /* 注意乘以2 */ for(int i=0;i<100000;i+=2) if(getT(i)==1) printf("%d\n", i/2); return 0; }