关于那个所谓的腾讯笔试题的研究

今天看见一个腾讯笔试题,正好研究了一下大内存操作和文件映射等问题。

题目是:一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数

算法一:分配512MB内存,每一bit代表一个整数,测试程序(VC6)如下:


    //一个bit代表一个数,实际上只需要4096/8=512兆的内存空间((4096/32)*1024*1024个整数数组)

    //unsigned long p[(4096/32)*1024*1024];//栈默认不允许分配这么大的空间!!

 

    bool bFound = false;

    unsigned long *p,lResult;

    p = new unsigned long[(4096/32)*1024*1024];//这里堆分配这么大会较慢,约20秒,但可以完成

 

    //初始化内存,如果内存小,这句会很慢

    memset(p,0,(4096/8)*1024*1024);

 

    //直接读文件的办法:分段读入文件内容,把读入的内容4个字节一组当无符号整数处理

    //注意文件中的整数可能会重复,并且没有顺序排列

    /*FILE* stream = fopen("c://SkinPPDemo-VC.msi", "r");

    if (stream)

    {

       fseek(stream, 0, SEEK_SET);

       unsigned long lCur;

       while (fread(&lCur,4,1,stream) != NULL) //文件一大到这里就只能读一次成功(几M就算大)

       {

           p[lCur/32] |= 0x1 << (31 - lCur%32);

       }

       fclose(stream);

    }*/

 

    //以下使用内存映射的方法:由于文件有16G那么大,一次全映射也是不行的,要分多次

    HFILE hFile;

    OFSTRUCT opBuf;

    HANDLE hMapfile;

    HANDLE hMapview;

    BYTE *recv;

    hFile=OpenFile("c://SkinPPDemo-VC.msi",&opBuf,OF_READ);

    if (hFile==HFILE_ERROR)

    {

        printf("open file failed!/n");

        return ;

    }

    DWORD  dwSizeLow, dwSizeHigh;

    dwSizeLow = GetFileSize((HANDLE)hFile, &dwSizeHigh);

    hMapfile=CreateFileMapping((HANDLE)hFile,NULL,PAGE_READONLY,0,0,"MapTest");

    if(hMapfile==NULL || dwSizeLow == 0)

    {

        printf("mapping file failed!/n");

        return ;

    }

    CloseHandle((HANDLE)hFile);

    hFile=0;

    for(unsigned long l=0;l<=dwSizeHigh;l++)

    {

        const long READ_SIZE_EVERY_TIME = 1024 * 1024;//一次读入1

 

        long lReadTimes = l<dwSizeHigh ?

            (0xFFFFFFFF/READ_SIZE_EVERY_TIME + 1) : (dwSizeLow/READ_SIZE_EVERY_TIME + 1);

        for(unsigned long j=0;j< lReadTimes;j++)

        {

            if (l<dwSizeHigh || lReadTimes - 1 > j)

                hMapview=MapViewOfFile(hMapfile,FILE_MAP_READ,l,

                j*READ_SIZE_EVERY_TIME,READ_SIZE_EVERY_TIME);

            else //最后一次只映射最后一部分

                hMapview=MapViewOfFile(hMapfile,FILE_MAP_READ,l,

                j*READ_SIZE_EVERY_TIME,dwSizeLow%READ_SIZE_EVERY_TIME);

            if(hMapview==NULL)

            {

                printf("mapping view failed!/n");

                return ;

            }

            recv=(BYTE *)hMapview;

           

            BYTE *cur=recv;

            long lSize = ((lReadTimes - 1 > j) ?

                READ_SIZE_EVERY_TIME : (dwSizeLow%READ_SIZE_EVERY_TIME));

            while ( (cur - recv) < (lSize - 3))

            {

                unsigned long lCur = *(unsigned long*)cur;

 

                /*标识哪个数出现过了,bit的索引就代表那个数

                * 如果内存小,这句会导致循环很慢,可能因为页面文件和内存交互次数太多

                */

                p[lCur/32] |= 0x1 << (31 - lCur%32);

 

                cur += 4;

            }

           

            UnmapViewOfFile(hMapview);

        } 

    }

 

 

    //完成后,扫描一下数组p,找到第一个不存在的数

    for(unsigned long i=0;i<(4096/32)*1024*1024;i++)

    {

        if (p[i] < 0xFFFFFFFF)

        {

            //找到啦

            for(int j=0;j<32;j++)

            {

                if ((p[i] & (0x1 << (31-j))) == 0)

                {

                    lResult = i * 32 + j;//第一个不存在的数

                    bFound = true;

                    break;

                }

            }

        }

        if (bFound)

            break;

    }

    delete p;

注:如果直接用new申请动态内存,由于内存高达512兆,会很容易被交换到页面文件上去,效率会急剧下降,所以建议把内存申请在物理内存上,请参考VirtualAlloc和MapUserPhysicalPages(需要SDK)等的使用

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值