每个bit位都有0和1这两个状态,与此同时对于动态分配的一块内存是由一串bit流表示的,如果将第n个比特位为1理解成int类型的数n当前是存在的。我们就有了一个大数处理的方法,这种方法不仅效率高,而且非常节约内存。
它有很多应用,目前我想到几个,下午先完成了用bitmap对整数数列排序的方法。
要求:排序的数列必须是整数,数列中没有重复的数。
用到位域结构体,将每个字节都展现出来。
#pragma pack(1)
typedef struct
{
unsigned char b1 : 1;
unsigned char b2 : 1;
unsigned char b3 : 1;
unsigned char b4 : 1;
unsigned char b5 : 1;
unsigned char b6 : 1;
unsigned char b7 : 1;
unsigned char b8 : 1;
}bit_1_t;
typedef struct
{
unsigned char b1 : 2;
unsigned char b2 : 2;
unsigned char b3 : 2;
unsigned char b4 : 2;
}bit_2_t;
typedef struct
{
unsigned char b1 : 4;
unsigned char b2 : 4;
}bit_4_t;
#pragma pack()
将整数value“插入”到bitmap中。 bitSpan表示你用几个bit位去描述你插入的整数,一般情况下我们都习惯用1个比特位表示改整数是否存在。
但是如果要求你在bitmap中不但要表示出一个整数是否存在之外,还要你判断该整数是否出现1到多次,你就必须用到至少2个bit位去表示了。
/*
bitmap : the initialized bitmap byte arrary.
value : int number to be inserted.
bitSpan : the number of bit to represent an int value. The only supported value is 1, 2, 4, 8.
If value equals 1, one bit used for present the state of current int value.
If value equals 2, two bit is used. "00" means this int value is not exist. "01" means only one this value. "02" means two or more times this value appeared.
If value equals 4 or 8, 4 or 8 bits is used. And this bits value means the times of this int value have appeared.
*/
void insertIntoBitmap(char *bitmap, int value, int bitSpan)
{
int byteNum;
int byteOffset;
char *pointer;
unsigned char setVal;
unsigned char val;
if(NULL == bitmap)
{
cout << "bitmap is NULL." << endl;
return;
}
//printBitmap(bitmap, 2);
byteNum = (value * bitSpan)/8;
byteOffset = (value * bitSpan)%8;
pointer = bitmap + byteNum;
val = *pointer;
val <<= 8 - byteOffset - bitSpan;
val >>= 8 - bitSpan;
cout << "val=" << (int)val << endl;
switch(bitSpan)
{
case 1:
{
if(val == 0)
{
setVal = 1;
}
break;
}
case 2:
if(val == 0)//first time to insert.
{
setVal = 1;
}
else if(val == 1)
{
setVal = 2;
}
break;
case 4:
if(val < 0x0F)
{
setVal = val + 1;
}
break;
case 8:
if(val < 0xFF)
{
setVal = val + 1;
}
break;
default:
cout << "incorrect bitSpan value." << endl;
return;
}
//cout << "setVal=" << (int)setVal;
setVal <<= byteOffset;
//cout << " byteOffset=" << byteOffset << " byteNum=" << byteNum << " setVal=" << (int)setVal << endl;
*pointer |= setVal;
}
插入完毕后,我们得到了编码后的bitmap,只要对这个bitmap做相应的解码就可以输出我们想要的东西了。
下面这个函数就是从低地址向高地址遍历bitmap(我的系统是小顶堆,大顶堆的用户还要修改一下逻辑),然后将为1的比特位对应的整数依次赋给原始整型数组arr。这样得到的数组就是从小到大的排列。
参数: bitmap, bitmapLen, arr为整形数组, from为数组的起始点, end为结束点, bitSpan不说了。
void travelBitmap(char *bitmap, int bitmapLen, int *arr, int from, int end, int bitSpan)
{
char *pointer;
int i;
int arrIndex = from;
if(NULL == bitmap || NULL == arr)
{
cout<< "parameter error when travel bitmap." << endl;
return;
}
pointer = bitmap;
for(i = 0; i < bitmapLen; i++)
{
switch(bitSpan)
{
case 1:
{
bit_1_t *bit1;
bit1 = (bit_1_t *)&bitmap[i];
if(bit1->b1 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8;
arrIndex++;
}
if(bit1->b2 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8 + 1;
arrIndex++;
}
if(bit1->b3 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8 + 2;
arrIndex++;
}
if(bit1->b4 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8 + 3;
arrIndex++;
}
if(bit1->b5 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8 + 4;
arrIndex++;
}
if(bit1->b6 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8 + 5;
arrIndex++;
}
if(bit1->b7 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8 + 6;
arrIndex++;
}
if(bit1->b8 == 1 && arrIndex <= end)
{
arr[arrIndex] = i * 8 + 7;
arrIndex++;
}
break;
}
case 2:
break;
case 4:
break;
case 8:
break;
default:
break;
}
}
}
最后,看看这个排序算法,注意使用后要释放bitmap内存。
void bitmapSorting(int *arr, int size, int from, int end, char **bitmap)
{
int i;
int maxVal;
int bitSpan = 1;
int bitmapLen = 0;
if((NULL == arr) || (from > end) || (end >= size))
{
cout << "parameter error for bitmapSorting.." << endl;
return;
}
maxVal = arr[from];
for(i = from; i <= end; i++)
{
if(maxVal < arr[i])
{
maxVal = arr[i];
}
}
bitmapLen = (int)ceil(((maxVal + 1) * bitSpan)/8.0);
if((*bitmap = (char *)malloc(bitmapLen)) == NULL)
{
perror("malloc error in bitmapSorting.");
exit(0);
}
memset(*bitmap, 0, bitmapLen);
for(i = from; i <= end; i++)
{
insertIntoBitmap(*bitmap, arr[i], bitSpan);
}
printBitmap(*bitmap, bitmapLen);
travelBitmap(*bitmap, bitmapLen, arr, from, end, bitSpan);
}