php实现2-bitmap

14 篇文章 0 订阅

1.前言

先说一下什么是2-bitmap,为每个数分配2bit,00表示没有出现过,01表示出现过1次,10表示出现过2次及以上,11表示无意义。下面有个需求,求出一个数组中出现过一次的数字,显然用bitmap是无法实现的,位图法只能判断出是否出现过,但是只出现过一次是无法确定的,用2-bitmap正好能解决这种情况。

2.数据结构

既然连个bit表示一个数字,则能容纳的数字个数就是bitmap的一半


插入[1,4,3,7,7,6,10,15,30,15,7]后为


3.算法

这里有几个重要的地方,一是在插入一个数时要判断插入的数在数组中的状态,是没有出现过,还是出现过,二是状态的改变,未出现过,就将00变成01,如果出现过一次,就将01变成10,如果出现过多次,则不处理。

function bitMap2($arr) : array {
    $bitmap = array_fill(0,50,0);
    $int_bit_size = PHP_INT_SIZE * 4;
    foreach ($arr as $item){
        $bytePos = $item / $int_bit_size;
        $bitPos = $item % $int_bit_size;
        $status = findPosBitMapStatus($bitmap, $item);
        $position = 0;
        switch ($status){
            case 0 :{
                $position = 1 << ($bitPos*2);
            };
            break;
            case 1 :{
                $position = 2 << ($bitPos*2);
            };
            break;
            case 2 :;
        }
        //将对应为上的数值先清零,但是要保证其他位置上的数不变
        $bitmap[$bytePos] &= ~(3<<($bitPos*2));
        //将对应位上的二进制位改变成00,01,或10
        $bitmap[$bytePos] |= $position;
    }
    return $bitmap;
}

//查看这个数在2位图法中的状态,返回0,1,2,代表位出现过,出现过1次,出现过2次及以上。
function findPosBitMapStatus($bitMap, $number) : int {
    $int_bit_size = PHP_INT_SIZE * 4;
    $bytePos = $number / $int_bit_size;
    $bitPos = $number % $int_bit_size;
    $res = $bitMap[$bytePos]>>($bitPos*2) & 3;
    return $res;
}
//输出
function outPut2($bitMap){
    $int_bit_size = PHP_INT_SIZE * 4;
    foreach ($bitMap as $k=>$item){
        for ($i=0;$i<$int_bit_size;$i++){
            $flag = $item>>($i*2) & 3;
            if ($flag){
                $res = $k * $int_bit_size + $i;
                echo $res;
                echo "出现了".$flag."次";
                echo "<br>";
            }
        }
    }
}
$test_arr = array(1,4,3,7,7,6,10,15,30,15,7); //定义一个乱序的数组
$temp = bitMap2($test_arr);
outPut2($temp);

4.题

用位图法的好处就是能节约内存,比如这个题

在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数。这个就可以采用2-bitmap来解决这道题。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值