网易2013实习生试题 第五题

网易2013实习生试题:

5、请问func(0x7f530829)的返回值是()

  1. int func(unsigned int i)  
  2. {  
  3.     unsigned int temp = i;  
  4.     temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa)>>1);  
  5.     temp = (temp & 0x33333333) + ((temp & 0xcccccccc)>>2);  
  6.     temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0)>>4);  
  7.     temp = (temp & 0xff00ff) + ((temp & 0xff00ff00)>>8);  
  8.     temp = (temp & 0xffff) + ((temp & 0xffff0000)>>16);  
  9.     return temp;  
  10. }  

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))了。

posted @ 2013-03-22 16:46  legendmaner  阅读(341)  评论(0编辑  收藏  举报