bitmap

bitmap是一个非常有用的结构。所谓的bitmap是用一个bit位来标记某个元素对应的value,而key即是该元素。

例如bitmap[key]=0x1;表示key这个元素有出现。

由于采用了bit为单位来存储数据,因此在存储空间方面,可以大大节省。

使用范围:可进行数据的快速查找,判重,删除,一般来说数据范围在int的10倍以下.

问题实例:
1.已知某个文件包含一些电话号码,每个号码为8位数字,统计不同号码的个数。

思路:

8位最多为9999 9999,大概需要99Mb,即十几MB的内存。

#include <iostream>
using namespace std;
#include <fstream>

const int MAX = 99999999;
char *g_bitmap = NULL;
int g_size = 0;
int g_base = 0;
//功能:初始化bitmap 
//参数: size:bitmap的大小,即bit位的个数 
//      start:起始值 
//返回值:0表示失败,1表示成功 
int bitmap_init(int size, int start)
{
	g_size = size / 8 + 1;
	g_base = start;
	g_bitmap = new char[g_size];
	if (g_bitmap == NULL)
	{
		return 0;
	}
	memset(g_bitmap, 0x0, g_size);
	return 1;
}
//功能:将值index的对应位设为1 
//index:要设的值 
//返回值:0表示失败,1表示成功 
int bitmap_set(int index)
{
	int quo = (index - g_base) / 8;  //确定所在的字节
	int remainder = (index - g_base) % 8;  //字节内的偏移  
	unsigned char x = (0x1 << remainder);
	if (quo > g_size)
		return 0;
	g_bitmap[quo] |= x;   //所在字节内的特定位置为1  
	return 1;
}

//功能:取bitmap第i位的值 
//i:待取位 
//返回值:-1表示失败,否则返回对应位的值 
int bitmap_get(int i)
{
	int quo = (i) / 8;
	int remainder = (i) % 8;
	unsigned char x = (0x1 << remainder);
	unsigned char res;
	if (quo > g_size)
		return -1;
	res = g_bitmap[quo] & x;
	return res > 0 ? 1 : 0;
}

//功能:返回index位对应的值   
int bitmap_data(int index)
{
	return (index + g_base);
}
//释放内存 
int bitmap_free()
{
	delete[] g_bitmap;
	return 0;
}

int main()
{
	bitmap_init(MAX, 0);
	ifstream in;
	in.open("phoneNumber.txt");
	if (!in.good()) {
		cout << "open failed" << endl; return 1;
	}
	int record;
	int count = 0;
	while (!in.eof())
	{
		in >> record;
		bitmap_set(record);
	}
	for (int i = 0; i <= MAX; i++)
	{
		if (bitmap_get(i) > 0)
		{
			cout << bitmap_data(i) << " ";
			count++;
		}
	}
	cout << endl;
	cout << count << endl;
	bitmap_free();
	in.close();
	return 0;
}


2. 2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。

思路:

将bitmap扩展一下,用2bit表示一个数,00表示没有出现,01表示出现一次,10表示出现两次或以上。这就是2bitmap

这样总共需要的内存为:

2^31*2bit=1Gb=128M(其中2^31表示unsigned int的个数)

注意:如果这2.5亿个数里面既有正数,又有负数,就要用两个2bitmap来分别存储,其中负数取绝对值后存储。

#include <iostream>
using namespace std;
#include <fstream>

const int MAX = 200000000;
char *g_bitmap = NULL;
int g_size = 0;

//功能:初始化bitmap 
//参数: size:bitmap的大小,即bit位的个数 
//      start:起始值 
//返回值:0表示失败,1表示成功 
int bitmap_init(int size)
{
	g_size = size / 8 + 1;
	g_bitmap = new char[g_size];
	if (g_bitmap == NULL)
	{
		return 0;
	}
	memset(g_bitmap, 0x0, g_size);
	return 1;
}

//功能:将值index的对应位设为1 
//index:要设的值
//num:bitmap中已经拥有index的个数
//返回值:0表示失败,1表示成功 
int bitmap_set(int index,int num)
{
	int quo = (index) / 4;  //确定所在的字节
	int remainder = (index) % 4;  //字节内的偏移  
	if (quo > g_size)
		return 0;
	g_bitmap[quo] &= ~((0x3 << (2 * remainder))&0xff); //将index对应位上的数值先清零,但是保证其他位不变
	g_bitmap[quo] |= ((num % 4) << (2 * remainder)&0xff); //重新对index的个数赋值
	return 1;
}

//功能:取bitmap第i位的值 
//i:待取位 
//返回值:-1表示失败,否则返回对应位的值 
int bitmap_get(int i)
{
	int quo = (i) / 4;
	int remainder = (i) % 4;
	if (quo > g_size)
		return -1;
	int res = (g_bitmap[quo] & (0x3 << (2 * remainder))) >> (2 * remainder);
	return res;
}

//功能:增加一个   
unsigned add_one(int index)
{
	if (bitmap_get(index) >= 2) return 1;   //这一位置已经出现
	else bitmap_set(index, bitmap_get(index) + 1);
	return 0;
}

//释放内存 
int bitmap_free()
{
	delete[] g_bitmap;
	return 0;
}

int main()
{
	bitmap_init(MAX);
	ifstream in;
	in.open("phoneNumber.txt");
	if (!in.good()) {
		cout << "open failed" << endl; return 1;
	}
	int record;
	int count = 0;
	while (!in.eof())
	{
		in >> record;
		add_one(record);
	}
	for (int i = 0; i < MAX/2; i++)
	{
		if (bitmap_get(i) == 1)
		{
			cout << i << " ";
			count++;
		}
	}
	cout << endl;
	cout << count << endl;
	bitmap_free();
	in.close();
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值