bit-map海量数据处理

海量数据排序问题:文件包含1千万条电话号码记录(10**7次方),每条记录都是7位整数,没有重复的整数。要求对文件进行排序,注意大约只有1MB的内存空间可用,有充足的磁盘存储空间可用。请设计一个高效的算法。
  (1)运用多趟算法:如果每个号码都使用32位整数来表示,则在1MB存储空间里大约可以存250000个号码。因此,可以使用遍历输入文件40趟的程序来完成排序。在第一趟中,将0至249999之间的任何整数读入内在,对其进行排序后写到输出文件中。第二趟遍历250000至499999之间的整数,依此类推,到第40趟遍历的时候对9750000至9999999之间的整数进行排序。
  (2)运用位图数据结构:使用一个具有1000万个位的串(约1.25MB)来表示这个文件,其中当且仅当整数i在文件中存在时,第i位为1。首先将所有的位都置为0,从而将集合初始化为空。然后通过读入文件中的每个整数来建立集合,将每个对应的位都置为1。最后扫描每一位,如果该位为1就输出对应的整数,由此产生有序的输出文件。
#include <stdio.h>
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1+N/BITSPERWORD]; /* 表示1000万个整数的位向量 */
/* 设置整数i所在的位 */
void set(int i){
	/* a中每个元素能表示32个整数,因此表示整数i的位是元素a[i/32]中的某个位,
	   这个位在a[i/32]的左越第i & 5(i的末五位表示的整数)个位处
	*/
	a[i>>SHIFT] |= (1<<(i & MASK));
}
/* 清除整数i所在的位 */
void clr(int i){
	a[i>>SHIFT] &= ~(1<<(i & MASK));
}
/* 测试位向量中是否有整数i */
int test(int i){
	return a[i>>SHIFT] & (1<<(i & MASK));
}
int main(void){
	int i;
	for(i=0;i<N;++i)
		clr(i);
	while(scanf("%d",&i)!=EOF) //输入要排序的整数
		set(i);
	for(i=0;i<N;++i)
		if(test(i))
			printf("%d/n",i);
	return 0;
}


  (3)排序算法:用C标准库函数qsort,采用的是快速排序。

#include <stdio.h>  
#include <stdlib.h>  
int intcomp(int *x,int *y){  
	return *x-*y;  
}  
int a[10000000];  
int main(void){  
	int i,n=0;  
	while(scanf("%d",&a[n])!=EOF) //输入要排序的整数  
		n++;  
	qsort(a,n,sizeof(int),intcomp);  
	for(i=0;i<n;++i)  
		printf("%d\n",a[i]);  
	return 0;  
}  


  (4)基于集合的排序算法:用C++ STL中的set容器。

#include <cstdio>  
#include <iostream>  
#include <set>  
using namespace std;  
int main(void){  
	set<int> sint;  
	int i;  
	set<int>::iterator j;  
	while(cin>>i)  
		sint.insert(i); //会进行有序的插入  
	for(j=sint.begin();j!=sint.end();++j)  
		cout<<*j<<"\n";  
	return 0;  
}  


  海量数据搜索问题:一个顺序文件包含40亿个随机排列的32位整数,找出一个不在文件中的32位整数。
  (1)位图技术:如果有足够的内存,可以使用位图技术。使用536870912个8位字节形成的位图来表示文件的整数。通过扫描位图即可找到缺失的整数。
  (2)排序技术:通过对文件进行快速排序,我们能够找到缺失的整数。这时总的运行时间正比于nlogn。

  (3)二分搜索技术:如果仅有几百个字节的内存和几个外部的临时顺序文件可用呢?采用二分搜索技术并结合多趟算法。第一遍通过多趟读取40亿个输入整数,并把起始位为0的整数写入一个顺序文件,把起始位为1的整数写入另一个顺序文件。这两个文件中有一个文件最多包含20亿个整数,接下来将该文件用作当前输入并重复探测过程,但这次探测的是第第二个位。如果原始的输入文件包含n元素,那么第一遍将读取n个整数,第二遍最多读取n/2个整数,第三遍最多读取n/4个整数,依此类推,最后我们可以找到缺失的整数。所以总的运行时间正比于n。





BitMap的定义:所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。

 

使用bitmap实现8位电话号码的存储,能够实现电话号码的插入、删除、查找。

使用bitmap算法。8位电话号码总共有0-99999999个号码,每位代表一个电话号码,需要12500000个字节的内存来存储电话号码

实现过程如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define SZLONG_SIZE 5
#define SZLONG_MASK 31UL
#define __BIT_SET_N(n) (0x1<<(n&SZLONG_MASK))

void set_bit(void *base, unsigned long nr)
{
        unsigned long *m;
        unsigned long mask;

        m = (unsigned long *)base + (nr >> SZLONG_SIZE);
        mask = __BIT_SET_N(nr);
        *m = *m |mask;
}

void clear_bit(void *base, unsigned long nr)
{
        unsigned long *m;
        unsigned long mask;
        m = (unsigned long *)base + (nr >> SZLONG_SIZE);
        mask = __BIT_SET_N(nr);
        mask = ~mask;
        *m = *m&mask;
}

int main()
{
        unsigned long value = 0;

        set_bit(&value, 0);
        set_bit(&value, 30);
        printf("0x%08x\n", value);
        clear_bit(&value, 0);
        clear_bit(&value, 30);
        printf("0x%08x\n", value);
        return 0;
}



另外一个例子:

bitmap.h  
  
/* 
 *bitmap的c语言实现 
 *作者:bitileaf 
 *时间:2010-12-18 14:12 
 */  
#ifndef _BITMAP_H_   
#define _BITMAP_H_   
  
/* 
 *功能:初始化bitmap 
 *参数: 
 *size:bitmap的大小,即bit位的个数 
 *start:起始值 
 *返回值:0表示失败,1表示成功 
 */  
int bitmap_init(int size, int start);  
  
/* 
 *功能:将值index的对应位设为1 
 *index:要设的值 
 *返回值:0表示失败,1表示成功 
 */  
int bitmap_set(int index);  
  
/* 
 *功能:取bitmap第i位的值 
 *i:待取位 
 *返回值:-1表示失败,否则返回对应位的值 
 */  
int bitmap_get(int i);  
  
/* 
 *功能:返回index位对应的值 
 */  
int bitmap_data(int index);  
  
/*释放内存*/  
int bitmap_free();  
  
#endif   
   
bitmap.c  
  
#include <stdio.h>   
#include <stdlib.h>   
#include <string.h>   
#include "bitmap.h"   
  
unsigned char *g_bitmap = NULL;  
int g_size = 0;  
int g_base = 0;  
  
int bitmap_init(int size, int start)  
{  
    g_bitmap = (char *)malloc((size/8+1)*sizeof(char));  
    if(g_bitmap == NULL)  
        return 0;  
    g_base = start;  
    g_size = size/8+1;  
    memset(g_bitmap, 0x0, g_size);  
    return 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;  
    return 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;   
}  
  
int bitmap_data(int index)  
{  
    return (index + g_base);  
}  
  
int bitmap_free()  
{  
    free(g_bitmap);  
}  
   
测试程序bitmap_test.c:  
  
#include <stdio.h>   
#include "bitmap.h"   
  
int main()  
{  
    int a[] = {5,8,7,6,3,1,10,78,56,34,23,12,43,54,65,76,87,98,89,100};  
    int i;  
    bitmap_init(100, 0);  
    for(i=0; i<20; i++)  
        bitmap_set(a[i]);  
    for(i=0; i<100; i++)  
    {  
        if(bitmap_get(i) > 0 )  
            printf("%d ", bitmap_data(i));  
    }  
    printf("/n");  
    bitmap_free();  
    return 0;  
}  



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值