巧用位运算进行排序、去重

排序举例:

一个4G内存的系统,一个文件存储了9亿条不重复的9位数,现在要对这个文件进行排序

方法1:内存中进行排序(快速排序,插入排序,堆排序,归并排序等)

我们来分析下,9位数需要用int或者unsigned int类型来表示,4个字节,9亿 * 4字节= 36亿字节 = 3433M内存,对于4G内存的系统,访问3.4G的内存,难度很大,因为这种方法行不通

方法2:在数据库中进行排序

只需要读取文件后导入数据库,进行排序即可。缺点:要有数据库等设备

方法3:使用位运算进行排序

9位数的范围也就是0-999999999,一共10亿个数字,如果我们为每一个数字用一个位(bit)来表示存在还是不存在,一共只需要10亿位= 1.25亿字节 = 119M,这样很容易申请内存。

具体办法:申请一块10亿位(1.25亿字节)的数组,全部初始化为0。依次读取文件中的数字,把该数字对应的位上标记为1表示已存在。比如数字987654321,在内存中移位到987654321对应的位,设置为1。最后,从低位到高位(或从高位到低位)遍历整个数组,为1的说明存在该数,写入到文件中即可

优点:我们用一个位(bit)来表示一个9位数,而不是一个int(32bit),这样数据量压缩了32倍

缺点:只适用于不重复的数字排序,因为一旦有重复,一个位(bit)为1时,我们没法知道有多少个重复的数字。

核心代码:

1. 检测指定字符的指定位的数是否为1

// 判断字符dest的第second位是否为1
bool IsOne (unsigned char dest, int second)
{
    const static int mark[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
    if (second>=8 || second <0) 
    {
        return false;
    }
    return (dest & mark[second]) == mark[second];
 }

2. 将指定字符的指定位的数置为1

// 将字符dest的第second位改为1
bool SetOne (unsigned char* dest, int second)
{
    const static int mark[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
    if (second>=8 || second <0) 
    {
        return false;
    }
    *dest |= mark[second];
    return true;
}

去重举例1:

一个文件中有10亿条中国地区的手机号码,我们要删除其中重复的手机号码

分析如下:

一个手机号码有11位,优化一下,我们认为第一位永远是1,不予考虑,只需检测后面的10位数字

10位数字的范围是0-9999999999,一共100亿个数字

按照上面的办法,以一个位来表示一个数字,申请一块10亿位(10亿bit = 119M)的数组

依次读取文件,处理某个数字时,如果对应位置为0则标记为1;如果对应位置为1则说明数字重复,不需处理

去重举例2:

40亿个的QQ号(QQ号用unsigned int表示),要求去重,只给1G内存

分析如下

unsigned int是用4个字节表示,范围0-4294967295,差不多43亿个数字

按照上面的办法,以一个位来表示一个数字,申请一块43亿位(43亿bit = 512M)的数组

依次读取QQ号,处理某个数字时,如果对应位置为0则标记为1;如果对应位置为1则说明数字重复,不需处理

注意事项

由于操作系统或者编程语言本身的限制,有可能系统内存足够,仍然无法分配一块连续大内存的情况,这样的话可以申请多块稍微小一点的内存,然后用链表或其他的方式连接起来使用,只是判断或者标记的时候需要计算一下具体的位置

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值