操作二进制的(记录)

问题1

给你一个值(char,int....),当然他们在内存中都是二进制存在的,怎么反转它们的值呢?

int型

比如  (0x00006CBA)  0000 0000  0000 0000   0110 1100  1011 1010 (27834) 

二进制和十六进制不熟,直接计算器(囧)

这个数比较小,只是举个例子, 我们直接用眼睛瞅可以得出:

0101 1101  0011 0110  0000 0000  0000 0000 => 1563820032 (0x5D360000)

显然,容易瞅错,要是别人问你,或者你面试,面试官难为你,你这不就笑话了么....还得随带个计算器...

扯淡哈.....

这就涉及到一个算法,叫做 分治法 

https://baike.baidu.com/item/%E5%88%86%E6%B2%BB%E6%B3%95/2407337?fr=aladdin

我的粗糙理解就是,取最小的问题解决,然后扩大(一般是倍数),直到解决问题,在实现上递归式比较常用的。

扯远...

用到这个题上就是,你想倒转,那我从最小组的倒转,自己和自己换没意义,那我就相邻的两个换。各两个互换后,他俩成为一组在和相邻的别的组互换....当只有两组的时候,他俩一换,全部倒腾完了...

参见一个小伙伴的讲解:

https://blog.csdn.net/u013074465/article/details/45485959

当然 出现了这么几个神奇的二进制数

0x5555555555555555(long) (0101010101010101010101010101010101010101010101010101010101010101)

太长了,一下用x86int来解说:

0x55555555 =     (01010101010101010101010101010101) (1431655765)如果你的调试器好你可以看到整数。

0xAAAAAAAA = (10101010101010101010101010101010)  (2863311530)

0x33333333  =     (00110011001100110011001100110011) 

0xCCCCCCCC =(11001100110011001100110011001100)

0x0f0f0f0f

0xf0f0f0f0

0x00ff00ff

0xff00ff00

0x0000ffff

0xffff0000   以下自行二进制............

看着16进制好怪,无非就是二进制各位不同,就是每一位和其余都不相同意思,由于是二进制,所以一定是10,扩大组就变成

1100  1111000 .... 依次

用干啥呢,用来反转的

num = ((num >> 1) & 0x55555555) | ((num << 1) & 0xAAAAAAAA);

当参数 v >> 右移1,与(0x05) 0101 相与(留奇),得到 把偶数位放到奇数上,把偶数上位变零

当参数 v << 左移1,与(0x0A) 1010 相与(留偶),得到 把奇数位放到偶数上,把奇数上位变零

然后相加(+)或者相或(|),就达到了两位两位反转的目的。

然后利用递归原理,扩大分组, << 右移2   >>左移 2  , 与 0011(留奇)  1100(留偶)

<< 右移4   >>左移 4  , 与 0001111(留奇)  11110000(留偶)

至于多大取决于你的字节长度,如果是int,那么 16 就可以了 32 位么,最后一次到移位16 就完成目标啦,

当然你要是long或者更大,那就看你自己平台了,long 应为 64 位,八个字节,那就在>>32吧。

所以有一下算法:类C实现(int)

        private static long Number5(uint num)
        {
            num = ((num >> 1) & 0x55555555) | ((num << 1) & 0xaaaaaaaa);
            num = ((num >> 2) & 0x33333333) | ((num << 2) & 0xcccccccc);
            num = ((num >> 4) & 0x0f0f0f0f) | ((num << 4) & 0xf0f0f0f0);
            num = ((num >> 8) & 0x00ff00ff) | ((num << 8) & 0xff00ff00);
            num = ((num >> 16) & 0x0000ffff) | ((num << 16) & 0xffff0000);
            return num;
        }

神奇有没有,对于不熟悉二进制的上层程序员,不研究一会真不知道他们整的是啥....

 

问题2

查出一个int类型数二进制有多少个1。

我个菜鸟,绞尽脑汁:

 private static int Number(int figure)
 {
      var cout = 0;
      var temp = figure;
      while (temp != 0)
      {
         var c = (temp & 1);
         if (c == 1) cout++;
         temp = temp >> 1;
       }
       return cout;
 }

然后看见更好的算法...

 private static  int Number(int figture)
        {
            int num = 0;
            while (figture > 0)
            {
                figture &= (figture - 1);
                num++;
            }
            return num;
        }

然后分治法又出来了...

        private static int Number2(int a)
        {
            a = (a & 0x55555555) + ((a >> 1) & 0x55555555);
            a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
            a = (a & 0x0f0f0f0f) + ((a >> 4) & 0x0f0f0f0f);
            a = (a & 0x00ff00ff) + ((a >> 8) & 0x00ff00ff);
            a = (a & 0x0000ffff) + ((a >> 16) & 0x0000ffff);
            return a;
        }

看看小伙伴的文章:

https://blog.csdn.net/youdianmengxiangba/article/details/8179832?utm_source=blogxgwz0

然后这个我也看懂了:

        private static int Number4(long x)
        {
            x -= (x >> 1) & 0x5555555555555555;           
            x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
            x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
            x += x >>  8;
            x += x >> 16;
            x += x >> 32;
            return x &0xff;
        }

然后看不懂了...

int static  Number5(long x) {
    x -= (x >> 1) & m1;             
    x = (x & m2) + ((x >> 2) & m2); 
    x = (x + (x >> 4)) & m4;        
    return (x * h01)>>56;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 
}

行吧,程序猿的世界,总是有看不懂代码,先记下来,没事再烧烧脑....

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值