赞
踩
位图(Bitmap)是一种特殊的序列结构,可用以动态地表示由一组(无符号)整数构成的集合。
若是32位,则长度U为 2 32 2^{32} 232,且其中每个元素的取值均为布尔型(初始值均为 false)。
注意:bit的最小操作单位是8位,n+ 7是在做ceiling。
算法思想:
上述接口实现
class Bitmap { //位图Bitmap类 private: unsigned char* M; Rank N, _sz; //位图空间M[],N*sizeof(char)*8个比特中含_sz个有效位 protected: void init( Rank n ) { M = new unsigned char[N = ( n + 7 ) / 8]; memset( M, 0, N ); _sz = 0; } public: Bitmap( Rank n = 8 ) { init( n ); } //按指定容量创建位图(为测试暂时选用较小的默认值) Bitmap( char* file, Rank n = 8 ) { //按指定或默认规模,从指定文件中读取位图 init( n ); FILE* fp = fopen( file, "r" ); fread( M, sizeof( char ), N, fp ); fclose( fp ); for ( Rank k = 0, _sz = 0; k < n; k++ ) _sz += test(k); } ~Bitmap() { delete[] M; M = NULL; _sz = 0; } //析构时释放位图空间 Rank size() { return _sz; } void set ( Rank k ) { expand( k ); _sz++; M[k >> 3] |= ( 0x80 >> ( k & 0x07 ) ); } void clear ( Rank k ) { expand( k ); _sz--; M[k >> 3] &= ~ ( 0x80 >> ( k & 0x07 ) ); } bool test ( Rank k ) { expand( k ); return M[k >> 3] & ( 0x80 >> ( k & 0x07 ) ); } void dump( char* file ) //将位图整体导出至指定的文件,以便对此后的新位图批量初始化 { FILE* fp = fopen( file, "w" ); fwrite( M, sizeof ( char ), N, fp ); fclose( fp ); } char* bits2string( Rank n ) { //将前n位转换为字符串—— expand( n - 1 ); //此时可能被访问的最高位为bitmap[n - 1] char* s = new char[n + 1]; s[n] = '\0'; //字符串所占空间,由上层调用者负责释放 for ( Rank i = 0; i < n; i++ ) s[i] = test( i ) ? '1' : '0'; return s; //返回字符串位置 } void expand( Rank k ) { //若被访问的Bitmap[k]已出界,则需扩容 if ( k < 8 * N ) return; //仍在界内,无需扩容 Rank oldN = N; unsigned char* oldM = M; init( 2 * k ); //与向量类似,加倍策略 memcpy_s( M, N, oldM, oldN ); delete[] oldM; //原数据转移至新空间 } };
1. 将非重复的ASCII字符视作一个集合,并将其组织为一个Bitmap结构——ASCII编码为k的字符,对应于其中第k个比特位。
2. 初始时,该集合为空,Bitmap结构中的所有比特位均处于0状态。以下,只需在O(n)时间内遍历所有的输入字符,并对
ASCII编码为k的字符,通过set(k)接口将其加入集合。
3. 请注意,这里使用的Bitmap结构只需128个比特位。因此,最后只需再花费O(128) = O(1)时间遍历一趟所有的比特位,
并输出所有通过test()测试的比特位,即可完成字符集的去重。
#include "../Bitmap/Bitmap.h" //引入Bitmap结极 /****************************************************************************************** * 筛法求素数 * 计算出不大于n的所有素数 * 不计内循环,外循环自身每次仅一次加法、两次判断,累计O(n) * 内循环每趟迭代O(n/i)步,由素数定理至多n/ln(n)趟,累计耗时不过 * n/2 + n/3 + n/5 + n/7 + n/11 + ... * < n/2 + n/3 + n/4 + n/6 + n/7 + ... + n/(n/ln(n)) * = O(n(ln(n/ln(n)) - 1)) * = O(nln(n) - nln(ln(n)) - 1) * = O(nlog(n)) * 如下实现做了进一步优化,内循环从i * i而非i + i开始,迭代步数由O(n / i)降至O(max(1, n / i - i)) ******************************************************************************************/ void Eratosthenes ( int n, char* file ) { Bitmap B ( n ); B.set ( 0 ); B.set ( 1 ); //0和1都不是素数 for ( int i = 2; i < n; i++ ) //反复地,从下一 if ( !B.test ( i ) ) //可认定的素数i起 for ( int j = 2*i; j < n; j += i ) //以i为间隔 B.set ( j ); //将下一个数标记为合数 B.dump ( file ); //将所有整数的筛选标记统一存入指定文件,以便日后直接寻入 }
该算法可在O(nlogn)时间内计算出不超过n的所有素数。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。