位图法

    技术2022-05-18  33

    在 8K 字节的内存空间内,如何存 unsigned short 类型数据?

    一般做法:

    定义一个数组: unsigned short arrNormal[4096];

    这样做,最多只能存 4K 个 unsigned short 数据。

     

    利用位图法:

    定义一个数组: unsigned char arrBit[8192];

    这样做,能存 8K*8=64K 个 unsigned short 数据。

     

    写数据元素:计算待写入数据在 arrBit 存放的字节位置和位位置(字节 0~8191 ,位 0~7 )

     

    比如写 1234 ,字节序: 1234/8 = 154; 位序: 1234 & 0b111 = 2 ,那么 1234 放在 arrBit 的下标 154 字节处,把该字节的 2 号位( 0~7 )置为 1

          

    字节位置: int nBytePos = 1234/8 = 154;

    位位置:   int nBitPos = 1234 & 7 = 2;

     

    // 把数组的 154 字节的 2 位置为 1

    unsigned short val = 1<<nBitPos;

    arrBit[nBytePos] = arrBit[nBytePos] | val;  // 写入 1234 得到 arrBit[154]=0b00000100

     

    此时再写入 1236 ,

    字节位置: int nBytePos = 1236/8 = 154;

    位位置:   int nBitPos = 1236 & 7 = 4

     

    // / 把数组的 154 字节的 4 位置为 1

    val = 1<<nBitPos;

    arrBit[nBytePos] = arrBit[nBytePos] | val;  // 再写入 1236 得到 arrBit[154]=0b00010100

     

    读数据元素:按位读取 arrBit ,取得位为 1 的字节位置和位位置。元素值为 8* nBytePos + nBitPos

    for (i=0; i<8192; i++)

    {

           for (j=0; j<8; j++)

           {

                  if (arrBit[i] & (1<<j))

                  {

                         cout << "arrBit:" << i << " " << j << "     " << 8*i+j << endl;

                  }

           }

    }

    会输出:

    arrBit:154 2     1234

    arrBit:154 4     1236

     

    删除元素:计算待删除元素的字节位置和位位置: arrBit[nBytePos] &= ~(1<< nBitPos);

    比如删除 1234 : arrBit[154] &= ~(1<<2);

     

    位图法的缺点:

    1. 可读性差

    2. 位图存储的元素个数虽然比一般做法多,但是存储的元素大小受限于存储空间的大小。

       位图存储性质:存储的元素个数等于元素的最大值。

       比如, 1K 字节内存,能存储 8K 个值大小上限为 8K 的元素。(元素值上限为 8K ,这个局限性很大!)

       比如,要存储值为 65535 的数,就必须要 65535/8=8K 字节的内存。要就导致了位图法根本不适合存 unsigned int 类型的数(大约需要 2^32/8=5 亿字节的内存)。

    3. 位图对有符号类型数据的存储,需要 2 位来表示一个有符号元素。这会让位图能存储的元素个数,元素值大小上限减半。

       比如 8K 字节内存空间存储 short 类型数据只能存 8K*4=32K 个,元素值大小范围为 -32K~32K 。

    综上所诉:位图法的适用范围很特殊。

     

     

     

    #include<iostream> //#include<vector> using namespace std; const int max=500000; //申请空间,字符数组byte[500000]可以表示500000*8个数 const int len=5; //数的个数 bool find(unsigned k,char num[]) { unsigned int a=k>>3; unsigned int b=k&7; if(num[a]&(1<<b)) return true; else return false; } int main() { char *arrBit=new char[max+1]; int n,nBtyePos,nBitPos; memset(arrBit,0,(max+1)); cout<<"输入"<<len<<"个数:"<<endl; for(int i=0;i<len;i++) { cin>>n; nBtyePos=n>>3; // n/8==n>>3 nBitPos=n&7; // n%8==n&7 arrBit[nBtyePos]=arrBit[nBtyePos]|1<<nBitPos; } int des; cout<<"输入要查找的数"<<endl; cin>>des; if(find(des,arrBit)) cout<<"存在"<<endl; else cout<<"不存在"<<endl; delete []arrBit; return 0; }

     

     

    有2.5亿个整数(这2.5亿个整数存储在一个数组里面,至于数组是放在外存还是内存,没有进一步具体说明); 要求找出这2.5亿个数字里面,不重复的数字的个数(那些只出现一次的数字的数目); 另外,可用的内存限定为600M; 要求算法尽量高效,最优; 1. caoxic的算法 BYTE marks[2^29];//512M // BYTE marks[2^32/8]; //用这个就更清楚了,标志所有整数(2^32)出现的可能 BYTE repmarks[2^25];//32M 32M*8>2.5亿 //标志2.5亿个数字数组里面的数字是否重复过 const BYTE bitmarks[8]={1,2,4,8,16,32,64,128}; DWORD CalcDifNum(DWORD *pBuf,DWORD bufcount) { DWORD dw ; DWORD count = 0 ;// 不重复的数字(包括出现多次的数字,只算一个)的个数,例子:1 2 2 3 5 3 4 算5个 DWORD count2 = 0 ;//重复出现的数字的个数,例子:1 2 2 3 5 3 4 算2个 memset(marks,0,sizeof(marks)); memset(repmarks,0,sizeof(repmarks)); ASSERT(sizeof(repmarks)*8>=bufcount);//断言repmarks数组够用 for(dw=0;dw<bufcount;dw++) { if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7]) { repmarks[dw>>3] |= bitmarks[dw&7];//标志pBuf[dw]这个数字出现重复 } else { count ++; marks[pBuf[dw]>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现 } } memset(marks,0,sizeof(marks)); for(dw=0;dw<bufcount;dw++) { if(repmarks[dw>>3] & bitmarks[dw&7])// { if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7]) { } else { count2 ++; //重复的数字的数量 marks[pBuf[dw]>>3] |= bitmarks[pBuf[dw]&7]; } } } return count-count2; } 2. 改一下,应该也可以: BYTE marks[2^29];//512M // BYTE marks[2^32/8]; //用这个就更清楚了,标志所有整数(2^32)出现的可能 BYTE repmarks[2^25];//32M 32M*8>2.5亿 //标志2.5亿个数字数组里面的数字是否重复过 const BYTE bitmarks[8]={1,2,4,8,16,32,64,128}; DWORD CalcDifNum(DWORD *pBuf,DWORD bufcount) { DWORD dw ; DWORD count = 0 ;// 不重复的数字(包括出现多次的数字,只算一个)的个数,例子:1 2 2 3 5 3 4 算5个 DWORD count2 = 0 ;//只出现一次数字的个数,例子:1 2 2 3 5 3 4 算3个 memset(marks,0,sizeof(marks)); memset(repmarks,0,sizeof(repmarks)); ASSERT(sizeof(repmarks)*8>=bufcount);//断言repmarks数组够用 for(dw=0;dw<bufcount;dw++) { if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7]) { repmarks[dw>>3] |= bitmarks[dw&7];//标志pBuf[dw]这个数字出现重复 } else { count ++; marks[pBuf[dw]>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现 } } for(dw=0;dw<bufcount;dw++) { if(!(repmarks[dw>>3] & bitmarks[dw&7]))//非重复的位置 { count2 ++; //只出现一次的数字的数量 } } return count2; }


    最新回复(0)