网易2013实习生试题 第五题
网易2013实习生试题:
5、请问func(0x7f530829)的返回值是()
- int func(unsigned int i)
- {
- unsigned int temp = i;
- temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa)>>1);
- temp = (temp & 0x33333333) + ((temp & 0xcccccccc)>>2);
- temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0)>>4);
- temp = (temp & 0xff00ff) + ((temp & 0xff00ff00)>>8);
- temp = (temp & 0xffff) + ((temp & 0xffff0000)>>16);
- return temp;
- }
A、15 B、16 C、17 D、18
函数实现的是求二进制表示的时候,1的个数,一共15个
最开始把每一个位看做一个节点,相邻节点值相加,结果用两个位表示。。。
然后每两个位看做一个节点,相邻节点值相加,结果用四个位表示。。。
以此类推,直到只剩下一个节点。。。
思考:1110
把每一个位看做一个节点,相邻节点值相加,相当于将他们以相邻为依据分为两组: [1,1] [1,0] 每组的1的和为 [1+1] [1+0] => [10][01](注意二进制)
现在结果为1001
将每两个位看做一个节点。相邻的就只有一组了:[10,01] 每组的1的和为[10+01]=>[0011],此时只有一组,结果就是这一组的1的个数了。
一开始,咋一看很神奇。其实仔细分析就明白。当成节点的时候,其意义不在是以前的意义了。而已表示为此个节点的1的个数了。节点也是不会溢出的,因为每次相加后进入到下次的阶段了。节点位数将翻倍增长,所以是不会溢出的。
扩充:
一段是不用循环,实现一个无符号整数的位交换(翻转0x00000002=》0x40000000)的程序:
unsigned bit_reverse( unsigned int n) { n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa); n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc); n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0); n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00); n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000); return n ; }
同一的道理。
不用除法实现%13操作(位操作)
使用除法很简单N= 13*(N/13) + mod。mod为N%13但是这里不能使用除法。
考虑:N%7不要模7运算
设N=8*(N/8)+mod8,mod8为N%8
N%7 = (8*(N/8)+mod8)%7 = (7*(N/8)+ (N/8)+mod8) %7 = ((N/8)+mod8) %7 = M%7 (设M=(N/8)+mod8)
求N%7化成了M%7,迭代下去,且N<=M,
当N<M时候说明M一直缩小,若M为0~7时可以返回结果就是M不在需要模7了。过程中只是用%8的运算(不使用模运算之后再说)
只有当N/8=0时才相等。即N为0~7时,可当为0~7时我们就可以直接得出结果了。
下面解释如何不用模8运算,以下红色字段摘于网络
描叙:
N= ( 8*x + y)
其中 x = N >> 3 , y = N &ox7 (这个意思其实就是x=N/8, y=N%8,自己琢磨吧,所以这样就可以不使用模8运算也可以)
N % 7 = ( 8 * x + y ) % 7 = (7 * x + x + y) % 7 = x + y
不断的迭代,知道 (x +y) < N 为止
%13 也是同样的道理:
虽然说是同样地道理其实它并没有说明白,下面是他给出的代码,有问题,你能找出来么?
#include"stdio.h" #include"stdlib.h" #define BITMOD 0xF #define BIT 4 #define MOD 13 int main() { int sNumber; int temp,temp1 ; int result[100]; int len = 0 ; printf("please input the source number:"); scanf("%d",&sNumber); temp = sNumber ; temp1 = sNumber ; while ( sNumber > MOD ) { temp = sNumber & BITMOD ; temp += 3 * ( sNumber >> BIT); sNumber = temp ; } if ( temp == MOD)
temp = 0 ;
printf("the number %d mod %d is : %d ",temp1 ,MOD, temp); return 0 ; }
其实是这样的。在给出的求模7的例子里面。是恰巧,使用了模8不断的减小数值。事实上刚才所说的,缩小到最后只能缩小在0到8-1=7范围的中。
而代码中使用同样地道理,用模16去所缩小数值。可是最后的只能缩小在0到16-1=15的范围中。如果缩小在0到13(13他刚好使用了其他的方式处理了)还好,这样可以直接出结果。可是,当14、15的是以上的代码将进入死循环了。
其实这整个思想就是通过移位实现到某种模A值运算,在使用这种模A值方式去减小模B值。其中B<A。但是缩小的规模只能映射在0~A-1中,这个范围可能比0~B-1大。模7例子比较巧,所以不要多做处理。但例如模13这个,这时要做相应的处理,因为处理的范围小,直接返回即可。这就是我看了红色这段的理解。
int func9(int num) { int temp,temp1 ; int len = 0 ; temp = num ; // temp1 = num ; while ( num > MOD ) { temp = num & BITMOD ; temp1 = 3 * ( num >> BIT); if (temp1==0) { if (temp1>MOD) { temp -= MOD; } } else { temp += temp1; } num = temp ; } if ( temp == MOD) temp = 0 ; return temp ; }
其实,这时你想问题模13不使用除法那不是容易么!!!如果一个正整数大于13,就一直将去13直到落于0~12的范围不就行了么?当然行,问题是时间复杂度为O(n),而我们使用的方法呢?可以这么考虑,每次向右移4位。n最大位数为log2(n),估值相当于O(log16(n))了。
毕