问题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) + ...
}
行吧,程序猿的世界,总是有看不懂代码,先记下来,没事再烧烧脑....