从2.5亿个数字里面找出不重复的数字的个数

本文介绍了一种高效的算法来解决在限定内存条件下查找大量整数中不重复数字的问题。通过对整数进行位操作标记,有效利用有限内存资源,实现快速统计。文中提供了三种不同的实现思路,帮助理解算法细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

整理自:http://topic.youkuaiyun.com/u/20070929/14/b183cd03-d780-4c59-a666-ab127f12f7b1.html 

问题描述如下:
有2.5亿个整数(这2.5亿个整数存储在一个数组里面,至于数组是放在外存还是内存,没有进一步具体说明);
要求找出这2.5亿个数字里面,不重复的数字的个数(那些只出现一次的数字的数目)
另外,可用的内存限定为600M;
要求算法尽量高效,最优;

1. caoxic的算法
BYTE    marks[2^29];//512M   // BYTE marks[2^32/8]; //用这个就更清楚了,标志所有整数(2^32)出现的可能
BYTE    repmarks[2^25];//32M 32M*8>2.5亿  //标志2.5亿个数字数组里面的数字是否重复过
const BYTE bitmarks[8]={1,2,4,8,16,32,64,128};
DWORD    CalcDifNum(DWORD
*pBuf,DWORD bufcount)
{
    DWORD dw ;
    DWORD count
= 0 ;// 不重复的数字(包括出现多次的数字,只算一个)的个数,例子:1 2 2 3 5 3 4 算5个
    DWORD count2 = 0 ;//重复出现的数字的个数,例子:1 2 2 3 5 3 4 算2个
    memset(marks,0,sizeof(marks));
    memset(repmarks,
0,sizeof(repmarks));
    ASSERT(
sizeof(repmarks)*8>=bufcount);//断言repmarks数组够用
    for(dw=0;dw<bufcount;dw++)
    {
       
if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7])
        {
            repmarks[dw
>>3] |= bitmarks[dw&7];//标志pBuf[dw]这个数字出现重复
        }
       
else
        {
            count
++;
            marks[pBuf[dw]
>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现
        }
    }

    memset(marks,
0,sizeof(marks));
   
for(dw=0;dw<bufcount;dw++)
    {
       
if(repmarks[dw>>3] & bitmarks[dw&7])//
        {
           
if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7])
            {
            }
           
else
            {
                count2
++; //重复的数字的数量
                marks[pBuf[dw]
>>3] |= bitmarks[pBuf[dw]&7];
            }
        }
    }
   
return count-count2;
}

2. 改一下,应该也可以:

BYTE    marks[2^29];//512M   // BYTE marks[2^32/8]; //用这个就更清楚了,标志所有整数(2^32)出现的可能
BYTE    repmarks[2^25];//32M 32M*8>2.5亿  //标志2.5亿个数字数组里面的数字是否重复过
const BYTE bitmarks[8]={1,2,4,8,16,32,64,128};
DWORD    CalcDifNum(DWORD
*pBuf,DWORD bufcount)
{
    DWORD dw ;
    DWORD count
= 0 ;// 不重复的数字(包括出现多次的数字,只算一个)的个数,例子:1 2 2 3 5 3 4 算5个
    DWORD count2 = 0 ;//只出现一次数字的个数,例子:1 2 2 3 5 3 4 算3个
    memset(marks,0,sizeof(marks));
    memset(repmarks,
0,sizeof(repmarks));
    ASSERT(
sizeof(repmarks)*8>=bufcount);//断言repmarks数组够用
    for(dw=0;dw<bufcount;dw++)
    {
       
if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7])
        {
            repmarks[dw
>>3] |= bitmarks[dw&7];//标志pBuf[dw]这个数字出现重复
        }
       
else
        {
            count
++;
            marks[pBuf[dw]
>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现
        }
    }

    for(dw=0;dw<bufcount;dw++)
    {
       
if(!(repmarks[dw>>3] & bitmarks[dw&7]))//非重复的位置
        {
                count2 ++; //只出现一次的数字的数量
        }
    }
   
return count2;
}

3. 把数组里面的数字分两类,正数负数,marks数组分成两部分标志,1.该数已经标志[0 -->  2^28-1] 2.标识该数已经重复[2^28 -->2^29-1]。

BYTE    marks[2^29];//512M   // BYTE marks[2^32/8]; //用这个就更清楚了,标志所有整数(2^32)出现的可能
const BYTE bitmarks[8]={1,2,4,8,16,32,64,128};
DWORD    CalcDifNum(DWORD *pBuf,DWORD bufcount)
{
    DWORD dw ;
    DWORD count = 0 ;// 不重复的数字(包括出现多次的数字,只算一个)的个数,例子:1 2 2 3 5 3 4 算5个
    DWORD count2 = 0 ;//重复出现的数字的个数,例子:1 2 2 3 5 3 4 算2个
    memset(marks,0,sizeof(marks));
    for(dw=0;dw<bufcount;dw++)
    {
        if(pBuf[dw]>=0)
        {
         if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7])
         {
            if(marks[2^28+pBuf[dw]>>3]&bitmarks[pBuf[dw]&7])
            {
            
            }else
            {
               marks[2^28+pBuf[dw]>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现重复
               count2 ++;
            }
         }
         else
         {
             count ++;
             marks[pBuf[dw]>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现
         }
        }
    }
   
    memset(marks,0,sizeof(marks));
    for(dw=0;dw<bufcount;dw++)
    {
        if(pBuf[dw]<0)
        {
         pBuf[dw] = -pBuf[dw];
         if(marks[pBuf[dw]>>3]&bitmarks[pBuf[dw]&7])
         {
            if(marks[2^28+pBuf[dw]>>3]&bitmarks[pBuf[dw]&7])
            {
            
            }else
            {
               marks[2^28+pBuf[dw]>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现重复
               count2 ++;
            }
         }
         else
         {
             count ++;
             marks[pBuf[dw]>>3] |= bitmarks[pBuf[dw]&7];//标志pBuf[dw]这个数字出现
         }
        }
    }
   
    return count-count2;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值