不重复整数的查找判断

      问题是这样:假设集合A中有 n 个整数,这些整数不重复,现给定一个数 i ,判断是否在A中。

      最容易想到的是将n个整数存入文件或内存中,然后顺序读取与 i 比较,但是如果n很大,那么这个过程就会花费很长的时间(和空间),因此需要一种更简洁有效的手段。

      再来看看信息:整数、不重复,也就是说每个整数的状态只有2种:存在或不存在,不用记录整数出现的次数。想到这里,我想起信号集的表示 sigset_t,  sigset_t表示的信号也只有2种状态,sigset_t用第 i 位为1表示有第 i 个信号,其本质是一个超大的整数。

因此可不可以用这种方法表示集合A呢?

      比如,定义一个bit位的集合,bit[n],用 bit[i]=0 表示整数 i 不存在,用bit[i]=1 表示整数 i 存在,

假设是32位机器,那么1B可以表示32个整数,1KB可以表示1024*32个整数,1MB就可以表示1024*1024*32=33 554 432个整数,可以看到用很小的空间开销就解决了存储问题。

      那么查询效率如何呢?显然查找 i 只需取bit[i]的值即可,查询效率为常数级。所以这种方法是可行且高效的。

      接下来问题来了,如何做这个bit[n]呢?在C中并没有bit的基本类型,常用的整数类型为int(32位),那么考虑将int看成32个bit的集合,

arr[1+n/32] 来作为存储n个整数的集合bit[n]。

      接下来是将第 i 个bit位置0或1的问题,涉及到bit位的,一般都是采用位操作的办法。以下是参照《编程珠玑》中的实现:可以看到全部由位操作实现,运行效率是很高的。

void set_bit(int i){
    arr[ i >> 5 ] |= ( 1 << ( i & 0x1F ));
    /*这里 i>>5 即 i/32,判断i在arr[]的哪一块中,
       找到该块后,需要将该块第 i%32 位置1(其他位不变),所以用 | 操作,
       (i & 0x1F) 就是求 i%32,1<<()即将第 (i&32) 位置1,其余位为0;*/
}
/*同理*/
void clear_bit(int i){
    arr[ i >> 5 ] &= ( 1 << ( i & 0x1F ));
    /*将第i位清0;*/   
}
int check_bit(int i ){
    return arr[ i >> 5 ] & ( 1 << ( i & 0x1F ));
    //查询第i位的值;
}

 

posted @ 2015-04-16 14:51  小白干  阅读(222)  评论(0编辑  收藏  举报