github地址:https://github.com/ALXlixiong/bitmap1
引:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。 【腾讯】
我的思路:拿到这道题首先想到的就是暴力求解法(O(N)),但是效率太慢;其次可从题中知40亿个数字无序,所以第二种思路就是排序+二分查找(O(NlgN)+O(lgN));还有一种思路就是哈希表+平衡搜索树(O(N)+O(lgN));
- 暴力求解法 O(N)
- 排序+二分查找 O(NlgN)+O(lgN)
- 哈希表+平衡搜索树 O(N)+O(lgN)
以上三种方法中,第二和第三中方法时间效率虽然和第一种时间效率差不多,但是两者有本质区别。第一种方法是一次性的,第二种和第三种是永久性的,只需要我们把数据组织好,以后查找效率O(lgN),所以后两种方法优于第一种。
但是40亿个数据(1G = 1024*1024*1024 byte )所以40亿int 需要内存4G*4(32位编译器),所以这些数据一定保存于磁盘,当然在磁盘中可以排序,但是效率太慢,而且后续需要二分查找,但是二分查找需要下标,所以不可行。所以上述三种方法都不可行。
上述三种方法都不可行,主要原因就是内存不够,那么我们想办法既可以判断该数字是否存在,又可以缩小空间。可以使用字符1表示存在,字符0表示不存在,那么我们可以假设预留>40亿的4G空间(此处假设42亿数字中包含了40亿数字)如果那么数字存在,把相应字符数组位置置为1,不存在置为0。这种方法下来大约需要4G空间,所以只要内存地址空间大和64位程序可能malloc出空间大小。
感觉上述方法还是不是最好的方法既然我们使用一个字符来保存1或者0,那么我们可以使用比特位来标识1或者0,那么我们可以采用位图。
位图
位图专门是解决数字存在与否,位图是直接定址法哈希表。
#include "bitmap.h"
void BitMapInit(BitMap *bp,unsigned int size)
{
assert(bp);
bp->capacity = size;
//需要多少个字节
//size>>5+1表示需要多少个int
bp->array = (int *)malloc(sizeof(int)*((size>>5)+1));
if(bp->array == NULL)
return;
bp->size = 0;
memset(bp->array,0,sizeof(int)*((size>>5)+1));
}
void BitMapSet(BitMap *bp,unsigned int data)
{
int index = data>>5;
int bit = data%32;
bp->size++;
bp->array[index] |= (1<<bit);
}
void BitMapReset(BitMap *bp,unsigned int data)
{
int index = data>>5;
int bit = data%32;
bp->size--;
bp->array[index] &= ~(1<<bit);
}
unsigned int BitMapIs(BitMap *bp,unsigned int data)
{
int index = data>>5;
int bit = data%32;
return (bp->array[index]>>bit) & 1;
}
void BitMapDestory(BitMap *bp)
{
free(bp->array);
bp->array = NULL;
bp->capacity = 0;
bp->size = 0;
}
void test()
{
BitMap bp;
BitMapInit(&bp,7);
BitMapSet(&bp,1);
BitMapSet(&bp,3);
BitMapSet(&bp,7);
BitMapSet(&bp,4);
BitMapSet(&bp,12);
BitMapSet(&bp,16);
printf("res_1 = %d\n",BitMapIs(&bp,1));
printf("res_1 = %d\n",BitMapIs(&bp,7));
printf("res_1 = %d\n",BitMapIs(&bp,12));
printf("res_1 = %d\n",BitMapIs(&bp,66));
printf("res_1 = %d\n",BitMapIs(&bp,2));
BitMapReset(&bp,7);
printf("res_1 = %d\n",BitMapIs(&bp,7));
BitMapDestory(&bp);
}
//bitmap.h
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef struct BitMap
{
int *array;//保存多少个int,对每个int里面的32个比特位操作
int capacity;
int size;
}BitMap;
void BitMapInit(BitMap *bp,unsigned int size);
void BitMapSet(BitMap *bp,unsigned int data);
void BitMapReset(BitMap *bp,unsigned int data);
unsigned int BitMapIs(BitMap *bp,unsigned int data);
void BitMapDestory(BitMap *bp);
void test();