bit-map牛刀小试:数组test[X]的值所有在区间[1, 8000]中, 现要输出test中反复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB

       先来看看这个题目:数组test[X]的值所有在区间[1, 8000]中。 现要输出test中反复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB.


       好, 我们先给出一个不限空间的解法(为了程序方便, 如果X为10, 实际上可能非常大):

#include <iostream>
using namespace std;

#define X 10
#define N 8000

// 输出反复的数字
void printDup(const int test[], int n)
{
	int a[N] = {0};
	int i = 0;
	for(i = 0; i < n; i++)
	{
		a[test[i] - 1]++;
	}

	for(i = 0; i < N; i++) // 注意, 此处是N而不是n
	{
		if(a[i] > 1)
		{
			cout << i + 1 << endl;
		}
	}
}

int main(void) 
{
	int test[X] = {1, 2, 3, 4, 2, 5, 6, 7, 5, N};
	printDup(test, X);
	
	return 0;
}

        结果为:

2

5


       显然, 上述程序在空间上超标(且当X<N=8000时。 时间超标), 究其原因是: 让一个int去存一个二值状态, 太浪费空间了。 和不用一个bit来存呢? 所以, 我们自然想到了用bit-map来操作。 例如以下:

#include <iostream>
using namespace std;

#define X 10

#define BIT_INT 32   // 1个int能够标志32个坑
#define SHIFT 5
#define MASK 0x1f
#define N 8000
int a[1 + N / BIT_INT]; // 须要1 + N / BIT_INT 个整数来标志N个事物

// 将全部位都初始化为0状态
void setAllZero()
{
	memset(a, 0, (1 + N / BIT_INT) * sizeof(int));
}

// 设置第i位为1
void setOne(int i)
{
	a[i >> SHIFT] |= (1 << (i & MASK));
}

// 设置第i位为1
void setZero(int i)
{
	a[i >> SHIFT] &= ~(1 << (i & MASK));
}

// 检查第i位的值
int getState(int i)
{
	return (a[i >> SHIFT] & (1 << (i & MASK))) && 1;
}

// 输出反复的数字
void printDup(const int test[], int n)
{
	int i = 0;
	for(i = 0; i < n; i++)
	{
		int state = getState(test[i] - 1);
		if(0 == state)
		{
			setOne(test[i] - 1);
		}
		else 
		{
			cout << test[i] << endl;
		}

	}
}

int main(void) 
{
	setAllZero();
	int test[X] = {1, 2, 3, 4, 2, 5, 6, 7, 5, N};
	printDup(test, X);
	
	return 0;
}
       结果为:

2

5


      且满足题目要求。 可是。 我随后发现这个程序还有个问题: 当test数组中某元素出现次数大于2时, 会反复输出。 比方:

#include <iostream>
using namespace std;

#define X 10

#define BIT_INT 32   // 1个int能够标志32个坑
#define SHIFT 5
#define MASK 0x1f
#define N 8000
int a[1 + N / BIT_INT]; // 须要1 + N / BIT_INT 个整数来标志N个事物

// 将全部位都初始化为0状态
void setAllZero()
{
	memset(a, 0, (1 + N / BIT_INT) * sizeof(int));
}

// 设置第i位为1
void setOne(int i)
{
	a[i >> SHIFT] |= (1 << (i & MASK));
}

// 设置第i位为1
void setZero(int i)
{
	a[i >> SHIFT] &= ~(1 << (i & MASK));
}

// 检查第i位的值
int getState(int i)
{
	return (a[i >> SHIFT] & (1 << (i & MASK))) && 1;
}

// 输出反复的数字
void printDup(const int test[], int n)
{
	int i = 0;
	for(i = 0; i < n; i++)
	{
		int state = getState(test[i] - 1);
		if(0 == state)
		{
			setOne(test[i] - 1);
		}
		else 
		{
			cout << test[i] << endl;
		}

	}
}

int main(void) 
{
	setAllZero();
	int test[X] = {1, 2, 3, 4, 2, 5, 6, 2, 5, N}; // 2出现3次
	printDup(test, X);
	
	return 0;
}
      结果为:

2

2

5


     我想了一下, 临时没有想到仅仅打印2, 5且符合题意的方法。 假设大家有好的思路, 欢迎赐教奋斗





 

posted @ 2016-02-21 08:58  lcchuguo  阅读(186)  评论(0编辑  收藏  举报