zoukankan      html  css  js  c++  java
  • 编程珠玑:位图法排序

    问题描述

    输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=107。如果在输入文件中有任何正数重复出现就是致命错误。没有其他数据与该正数相关联。

    输出:按升序排列的输入正数的列表。

    约束:最多有1MB的内存空间可用,有充足的磁盘存储空间可用。运行时间最多几分钟,运行时间为10秒就不需要进一步优化。

    程序设计与实现概要:

    应用位图或位向量表示集合。可用一个10位长的字符串来表示一个所有元素都小于10的简单的非负整数集合,例如,可以用如下字符串表示集合{1,2,4,5,8}:

    0  1  1  1  0  1  0  0  1  0  0

    代表集合中数值的位都置为1,其他左所有的位置为0.编程珠玑当中建议是一年个一个具有1000万个位的字符串来表示这个文件,那么这个文件的所占容量为10000000 bit=107bit,不到1MB的大小,其中,当且精当整数i在文件中存在,第i为1,这个表示利用了该问题的三个在排序问题中不常见的属性:输入数据限制在相对较小的范围内;数据没有重复;而且对于每条记录而言,除了单一个整数外没有其他关联数据。

    如给定表示文件中整数集合的位图数据结构,则可以分三个阶段来编写程序

    第一阶段:将所有的位都置为0,从而将集合初始化为空。

    第二阶段:通过读入文件中的每个整数来建立集合,将每个对应的位置都置为1。

    第三阶段:检验每一位,如果该为为1,就输出对应的整数,有此产生有序的输出文件。

    下面的C语言的实现和C++的实现代码

    C语言:

    所申请的int数组如下所示:

    字节位置=数据/32;(采用位运算即右移5位)

    位位置=数据%32;(采用位运算即跟0X1F进行与操作)。

    #include <stdio.h>
    #define MAX 10000000
    #define SHIFT 5           
    #define MASK 0x1F
    #define DIGITS 32
    
    
    int a[1+MAX/DIGITS];
    
    void set(int n)                                //将逻辑位置为n的二进制位置为1 
    {
        a[n>>SHIFT] |=(1<<(n&MASK));               //n>>SHIFT右移5位相当于除以32求算字节位置,n&MASK相当于对32取余即求位位置,
    }                                                
    
    void clear(int n)
    {
        a[n>>SHIFT] &=(~(1<<(n&MASK)));           //将逻辑位置为n的二进制位置为0
    }
    
    int test(int n)
    {
        return a[n>>SHIFT] & (1<<(n&MASK));        //测试逻辑位置为n的二进制位是否为1 
    }
    
    int main(int argc, char *argv[])
    {
        int i,n;
        for(i=1;i<=MAX;i++)
        {
            clear(i);
        }    
        while(scanf("%d",&n)!=EOF)
        {
            set(n);
        }
        for(i=1;i<=MAX;i++)
        {
            if(test(i))
                printf("%d ",i);
        }
        return 0;
    }

    C++(使用bitset)

    #include <iostream>
    #include<bitset> 
    
    using namespace std;
    
    
    int main(int argc, char *argv[])
    {
        const int max = 10000000;
        
        int n,i;
        bitset<max+1> bit;                     //初始默认所有二进制位为0 
        
        while(scanf("%d",&n)!=EOF)
        {
            bit.set(n,1);                   //将第n位置1               
        }    
        for(i=0;i<=max+1;i++)
        {
            if(bit[i]==1)
                printf("%d ",i);
        }
        return 0;
    }


    ---------------------------------------------------

     扩展:
     
    给40亿个不重复的unsigned int的整数,没有排过序,然后再给一个数,如果快速判断这个数是否在那40亿个数当中。(腾讯面试题)
     
    用位图法:40亿unsigned int,则用位图表示的话需要大小为40亿个bit=4*109 bit=0.5*109 bytes 因此申请的内存只需要大小约为512MB左右,这样在内存每个bit代表一个unsigned int整数,并将每个bit初始化为0,然后将40亿个unsigned int的整数读入,每个unsigned int的整数对应bit设置为1,读入后,最后看所给定的数对应的bit是否为1,是1存在,否则不存在。
     
     
  • 相关阅读:
    PHP生成PDF并转换成图片爬过的坑
    PHAR系列之导言
    Linux学习之路(三)Shell脚本初探
    Linux学习之路(二)
    php 隐藏手机号中间几位
    tp 递归菜单列表【树状】
    php导出excel封装类
    php 导出Excel表格
    php字符串之翻转单词顺序列
    laravel实现跳转其他控制器
  • 原文地址:https://www.cnblogs.com/biyeymyhjob/p/2636933.html
Copyright © 2011-2022 走看看