《Programming Pearls》(编程珠玑)第一章讲述了如何用位图排序无重复的数据集,整个思想很简洁,今天实践了下。

一、主要思想

  位图排序的思想就是在内存中申请一块连续的空间作为位图,初始时将位图的每一位都置为0,然后依次读取待排序文件的整数,将整数所在的位设置为1,最后扫描位图,如果某一位为1,则说明这个数存在,输出到已排序文件。比如待排序的数据S={3,0,4,1,7,2,5},max(S)=7,我们可以设置一个八位的位图B,将位图的每一位初始为0,即B=[0,0,0,0,0,0,0,0],对S中的每一个整数d,设置B[d]=1,即B=[1,1,1,1,1,1,0,1],最后扫描位图,对位图的每一位i,如果B[i]==1,则输出i到已排序文件,排序后的S={0,1,2,3,4,5,7}。

  整个过程只需要遍历一遍待排序文件和位图,时间复杂度O(n),需要的辅助空间为(max(S)/8)B。虽然这个排序算法只能在无重复的整数集上运行,但对于有些需求,确实做到高效实现,比如说给手机号码排序,手机号码11位,第一位始终为1,理论上可以有10^10个号码,但一些号码未发放,即有些号码在系统中不存在,假设系统中有50%的合法号码,每个号码用long int表示,这么多号码所需要的空间为50%*(10^10)*4B=20GB,不能放在内存中进行快速排序。一个可选的方案是分多趟进行归并排序,但需要较长的时间。我们申请一个10^10位的位图,需要的内存是10^10/8B=1.25GB,完全可以在当代的PC机上运行,在扫描位图时,假设某一位i为1,输出文件时,在前面添加一个1,例如i=3885201314,输出为13885201314。

二、算法实现

  用c语言实现的话,需要自己封装位图操作,这里需要用到三个操作:设置位图的所有位为0(setAllZero);设定指定的位为1(setOne);查看指定的位是否为1(find);代码如下:

 #include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h> #define MAX_NUM 16777216//最大的数,也就是需要的位
#define BYTE_NUM (1+MAX_NUM/8)//字节数
#define MASK 0x07 void setAllZero(unsigned char *p,long size);
void setOne(unsigned char *p,long loc);
int find(unsigned char *p,long loc);
bool getSorted(unsigned char *bitmap,char *fileName);
bool setBitmap(unsigned char *bitmap,char *fileName);
int bitmapSort();
int main(){
return bitmapSort();
}
int bitmapSort(){
unsigned char *bitmap; //位图指针
bitmap = (unsigned char *)malloc(BYTE_NUM*sizeof(unsigned char));
if(bitmap == NULL){
printf("Malloc failed\n");
return -;
}
setAllZero(bitmap,BYTE_NUM);//将位图所有位设置为0
setBitmap(bitmap,"phoneNumber.txt");//扫描待排文件,将位图对应位设置为1
getSorted(bitmap,"bitmapSort.txt"); //扫描位图,将位图为1的位号输出到文件
free(bitmap);//释放位图
return ;
}
/***********设置待排序数据的位图**************/
bool setBitmap(unsigned char *bitmap,char *fileName){
FILE *readFp;
printf("Setting bitmap...\n");
readFp = fopen(fileName,"r");
if(readFp == NULL)
return false;
long phoneNum=;
while(fscanf(readFp,"%ld\n",&phoneNum) != EOF){
setOne(bitmap,phoneNum);//将 phoneNum位设置为1
}
fclose(readFp);
return true;
}
/*****顺序遍历位图输出记录,从而实现排序****************/
bool getSorted(unsigned char *bitmap,char *fileName){
printf("Search bitmap...\n");
FILE *writeFp;
writeFp = fopen(fileName,"w");
if(writeFp == NULL)
return false;
long phoneNum=;
for(phoneNum = ; phoneNum < MAX_NUM; phoneNum += ){
if(find(bitmap,phoneNum)){
fprintf(writeFp,"%ld\n",phoneNum);
}
}
fclose(writeFp);
return true;
}
/******先将位图清零********/
void setAllZero(unsigned char *bitmap,long size){
for(long i=;i<size;i++)
*(bitmap+i) &= ;
}
/*************************************************
将指定的位置为1
(loc>>3)相当于整除2^3=8,即定位到字节数,MASK=0x07,loc&MASK相当于loc%8
***************************************************/
void setOne(unsigned char *bitmap,long loc){
*(bitmap+(loc>>)) |= (<<(loc&MASK));//
} /******查找指定的位是否为1********/
int find(unsigned char *bitmap,long loc){
return ((*(bitmap+(loc>>))) & (<<(loc&MASK))) == (<<(loc&MASK));
}

  C++的STL中有一个数据结构bitset,操作位图很方便。  

 #include <bitset>
#define MAX_NUM 4000000//最多的数,即需要的位数
using namespace std; int main(){
FILE *readFp,*writeFp;
readFp = fopen("phoneNumber1.txt","r");
writeFp = fopen("bitsetSorted.txt","w");
bitset<MAX_NUM> bitmap;
for(long i=;i<MAX_NUM;i++){//先将位图初试化为0
bitmap.set(i,);
}
printf("Begin set bitmap...\n");
long number = ;
while(fscanf(readFp,"%ld\n",&number) != EOF){
bitmap.set(number,);//将number所在位设置为1
}
printf("Begin search bitmap...\n");
for(long i=;i<MAX_NUM;i++){
if(bitmap[i] == )//将位1的位输出到已排序文件
fprintf(writeFp,"%ld\n",number);
}
fclose(writeFp);
fclose(readFp);
}

  排序算法很快就写好了,就开始生成测试数据,想生成0—2^31的乱序数据集还真不容易,首先要保证不重复,第二要丢掉40%的数(无效手机号码),第三要尽可能的乱序,捣了很久,最终还是找到了实现办法,生成了12GB的数据集,关于生成这个数据集的办法,欢迎一起讨论,我将会在下一篇中总结一下我的方法。

  完整的代码可以参考github

  感谢关注,欢迎评论。

  转载请注明出处:http://www.cnblogs.com/fengfenggirl/

疯狂位图之——位图实现12GB无重复大整数集排序的更多相关文章

  1. bitmap对海量无重复的整数排序--转

    原文地址:http://blog.csdn.net/u013074465/article/details/46956295 现在有n个无重复的正整数(n 小于10的7次方),如果内存限制在1.5M以内 ...

  2. 疯狂位图之——位图生成12GB无重复随机乱序大整数集

    上一篇讲述了用位图实现无重复数据的排序,排序算法一下就写好了,想弄个大点数据测试一下,因为小数据在内存中快排已经很快. 一.生成的数据集要求 1.数据为0--2147483647(2^31-1)范围内 ...

  3. 从无重复大数组找TOP N元素的最优解说起

    有一类面试题,既可以考察工程师算法.也可以兼顾实践应用.甚至创新思维,这些题目便是好的题目,有区分度表现为可以有一般解,也可以有最优解.最近就发现了一个这样的好题目,拿出来晒一晒. 1 题目 原文: ...

  4. 大数据位图法(无重复排序,重复排序,去重复排序,数据压缩)之Java实现

    1,位图法介绍 位图的基本概念是用一个位(bit)来标记某个数据的存放状态,由于采用了位为单位来存放数据,所以节省了大量的空间.举个具体的例子,在Java中一般一个int数字要占用32位,如果能用一位 ...

  5. [LeetCode] Longest Substring Without Repeating Characters 最长无重复子串

    Given a string, find the length of the longest substring without repeating characters. For example, ...

  6. 【python】题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

    # encoding:utf-8 # p001_1234threeNums.py def threeNums(): '''题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多 ...

  7. c#实现分组服务器,单一无重复生成ID

    class Program { static void Main(string[] args) { List<Thread> threads = new List<Thread> ...

  8. lintcode: 最长无重复字符的子串

    题目 最长无重复字符的子串给定一个字符串,请找出其中无重复字符的最长子字符串. 例如,在"abcabcbb"中,其无重复字符的最长子字符串是"abc",其长度为 ...

  9. hunnu 11313 无重复元素序列的最长公共子序列转化成最长递增子序列 求法及证明

    题目:http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11313 湖师大的比赛,见我的另一篇水题题解,这里要说的 ...

随机推荐

  1. Memcache笔记05-Memcache安全性

    Memcache服务器端都是直接通过客户端连接后直接操作,没有任何的验证过程,这样如果服务器是直接暴露在互联网上的话是比较危险,轻则数据泄露被其他无关人员查看,重则服务器被入侵,因为Mecache是以 ...

  2. Redis-stat的安装与使用

    redis-stat是一个用ruby写成的监控redis的程序,基于info命令获取信息,而不是通过monitor获取信息 一.安装ruby yum install -y ruby ruby-deve ...

  3. 【转】JAVA CAS原理深度分析

    java.util.concurrent包完全建立在CAS之上的,没有CAS就不会有此包.可见CAS的重要性. CAS CAS:Compare and Swap, 翻译成比较并交换. java.uti ...

  4. Eclipse中使用Git-让版本管理更简单

    详细步骤: 第一部分  GIT介绍 (1)GIT往世今生 2005年开发Samba的Andrew试图破解BitKeeper(一款商业的版本控制系统)的协议(这么干的其实也不只他一个),被BitMove ...

  5. Solr Dataimporthandler 导入MySQL 内存溢出。

    最近准备把一千九百多万数据导入Solr中,在以前测试数据只有一两百万,全量导入没有任务问题.但是,换成一千九百万数据时,solr报内存异常(java.lang.OutOfMemoryError:GC ...

  6. (转)github设置添加SSH

    很多朋友在用github管理项目的时候,都是直接使用https url克隆到本地,当然也有有些人使用 SSH url 克隆到本地.然而,为什么绝大多数人会使用https url克隆呢? 这是因为,使用 ...

  7. 【读书笔记《Android游戏编程之从零开始》】10.游戏开发基础(View 游戏框架)

    对于玩家来说,游戏是动态的:对于游戏开发人员来说,游戏是静态的,只是不停地播放不通的画面,让玩家看到了动态的效果. 进入Android之前,首先要熟悉三个重要的类:View(视图).Canvas(画布 ...

  8. 2014 Super Training #4 E Paint the Grid Reloaded --联通块缩点+BFS

    原题: ZOJ 3781 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3781 题意: 给一个n*m的X,O构成的格子,对 ...

  9. Flash Builder快捷键

    代码助手:Ctrl+Space(简体中文操作系统是Alt+/)快速修正:Ctrl+1单词补全:Alt+/打开外部Java文档:Shift+F2 显示搜索对话框:Ctrl+H快速Outline:Ctrl ...

  10. Spring AOP 针对注解的AOP

    我也忘记是从哪里扒来的代码,不过有了这个思路,以后可以自己针对 Controller 还有 Service层的任意 方法进行代理了 package pw.jonwinters.aop; import ...