zoukankan      html  css  js  c++  java
  • 采用bitmap位图算法对大量不重复数据进行线性时间排序

    /********************************************************************************* 
    问题描述
    输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10^7。
    如果在输入文件中有任何正数重复出现就是致命错误。没有其他数据与该正数相关联。
    输出:按升序排列的输入正数的列表。
    约束:最多有1MB的内存空间可用,有充足的磁盘存储空间可用。运行时间最多几分钟,
    运行时间为10秒就不需要进一步优化。
    32位机器上,一个整形,比如int a; 在内存中占32bit位,可以用对应的32bit位对应十进制的0-31个数,
    bitmap算法利用这种思想处理大量数据的排序与查询.
    优点:
    1.运算效率高,不许进行比较和移位;
    2.占用内存少,比如N=10000000;只需占用内存为N/8=1250000Byte=1.25M。
    缺点:所有的数据不能重复。即不可对重复的数据进行排序和查找。
    
    如给定表示文件中整数集合的位图数据结构,则可以分三个阶段来编写程序
    第一阶段:将所有的位都置为0,从而将集合初始化为空。
    第二阶段:通过读入文件中的每个整数来建立集合,将每个对应的位置都置为1。
    第三阶段:检验每一位,如果该为为1,就输出对应的整数,有此产生有序的输出文件。
    字节位置=数据/32;(采用位运算即右移5位)
    位位置=数据%32;(采用位运算即跟0X1F进行与操作)。
    思想比较简单,关键是十进制和二进制bit位需要一个map图,把十进制的数映射到bit位。
    下面详细说明这个map映射表。
    map映射表
    假设需要排序或者查找的总数N=10000000,那么我们需要申请内存空间的大小为int a[1 + N/32],
    其中:a[0]在内存中占32为可以对应十进制数0-31,依次类推:
    bitmap表为:
    
    a[0]--------->0-31
    a[1]--------->32-63
    a[2]--------->64-95
    a[3]--------->96-127
    ..........
    
    那么十进制数如何转换为对应的bit位,下面介绍用位移将十进制数转换为对应的bit位。
    位移转换
    1.求十进制0-N对应在数组a中的下标:
    十进制0-31,对应在a[0]中,先由十进制数n转换为与32的余可转化为对应在数组a中的下标。
    比如n=24,那么 n/32=0,则24对应在数组a中的下标为0。又比如n=60,那么n/32=1,
    则60对应在数组a中的下标为1,同理可以计算0-N在数组a中的下标。
    2.求0-N对应0-31中的数:
    十进制0-31就对应0-31,而32-63则对应也是0-31,即给定一个数n可以通过模32求得对应0-31中的数。
    3.利用移位0-31使得对应32bit位为1.
    
    解析:void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK)); }
    
    1.i>>SHIFT:
    其中SHIFT=5,即i右移5为,2^5=32,相当于i/32,即求出十进制i对应在数组a中的下标。
    比如i=20,通过i>>SHIFT=20>>5=0 可求得i=20的下标为0;
    2.i & MASK:
    其中MASK=0X1F,十六进制转化为十进制为31,二进制为0001 1111,i&(0001 1111)相当于保留i的后5位。
    比如i=23,二进制为:0001 0111,那么
    0001 0111
    & 0001 1111 = 0001 0111 十进制为:23
    比如i=83,二进制为:0000 0000 0101 0011,那么
    0000 0000 0101 0011
    & 0000 0000 0001 0000 = 0000 0000 0001 0011 十进制为:19
    i & MASK相当于i%32。
    3.1<<(i & MASK)
    相当于把1左移 (i & MASK)位。
    比如(i & MASK)=20,那么i<<20就相当于:
    0000 0000 0000 0000 0000 0000 0000 0001 >>20
    =0000 0000 0000 1000 0000 0000 0000 0000
    4.void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK)); }等价于:
    void set(int i)
    {
    	a[i/32] |= (1<<(i%32));
    }
    
    #define SIZEBIT 10000000
    #define SIZE SIZEBIT/32 + 1
    
    void cleanAll(unsigned int* bitmap)
    {
    	int i;
        for(i = 0; i < SIZE; ++i)
            bitmap[i] =0;
    }
    
    void set(unsigned int* bitmap, unsigned int index)
    {
        bitmap[index/32] |= 1 << index%32;
    }
    
    void clean(unsigned int* bitmap, unsigned int index)
    {
        bitmap[index/32] &= ~(1 << index%32);
    }
    
    int get(unsigned int* bitmap, unsigned int index)
    {
        return bitmap[index/32] & (1 << index%32);
    }
    
     
    **********************************************************************************/
    
    #include<stdio.h>
    #define MAX 10000000
    #define SHIFT 5
    #define MASK 0x1F
    #define DIGITS 32
    
    int a[1+MAX/DIGITS];
    //将逻辑位置为n的二进制位置为1
    void set(int n)
    {
        //n>>SHIFT右移5位相当于除以32求算字节位置,n&MASK相当于对32取余即求位位置,
    	a[n>>SHIFT] |=(1<<(n&MASK));
    }
    
    void clear(int n)
    {
        //将逻辑位置为n的二进制位置为0
    	a[n>>SHIFT] &=(~(1<<(n&MASK)));
    }
    
    int test(int n)
    {
         //测试逻辑位置为n的二进制位是否为1
    	return a[n>>SHIFT] & (1<<(n&MASK));
    }
    
    int main()
    {
        int i,n;
        for(i=1;i<=MAX;i++)
        {
            clear(i);
        }
        printf("\n please input data Ctrl+Z to stop !\n");
        while(scanf("%d",&n)!=EOF)
        {
            set(n);
        }
        printf("\n bitmap sort result is : \n");
        for(i=1;i<=MAX;i++)
        {
            if(test(i))
                printf("%d ",i);
        }
        printf("\n");
        return 0;
    }
    /*****************************
    
    please input data Ctrl+Z to stop !
    512
    420
    315
    51
    1105
    105
    
    1050
    426
    929
    47
    33
    2010
    2013
    ^Z
    
     bitmap sort result is :
    33 47 51 105 315 420 426 512 929 1050 1105 2010 2013
    
    Process returned 0 (0x0)   execution time : 83.070 s
    Press any key to continue.
    
    ******************************/
    


  • 相关阅读:
    第二十一章流 1流的操作 简单
    第二十章友元类与嵌套类 1友元类 简单
    第十九章 19 利用私有继承来实现代码重用 简单
    第二十章友元类与嵌套类 2嵌套类 简单
    第十九章 8链表类Node 简单
    第二十一章流 3用cin输入 简单
    第十九章 10 图书 药品管理系统 简单
    第十九章 11图书 药品管理系统 简单
    第二十一章流 4文件的输入和输出 简单
    第十九章 12 什么时候使用私有继承,什么时候使用包含 简单
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3047860.html
Copyright © 2011-2022 走看看