解题思路
我们可以用一个变量rbit
来记录x最右边的位移到最左端的位置(len(x) - 1),然后我们把x右移一位,再对右移后的x与rbit进行或操作,这就完成了一次对x的循环右移操作,我们操作n次即可完成。
//计算出运行程序的计算机所使用的字长
int wordlength()
{
int i;
unsigned v = (unsigned) ~0;
for(int i = 1; (v = v >> 1) > 0; ++i);
return i;
}
unsigned rightrot(unsigned x, int n)
{
int len = wordlength();
int rbit;
while(n-- > 0) {
rbit = (x & 1) << (len - 1);
x = x >> 1;
x = x | bit;
}
return x;
}
优化解法
如果对x进行循环右移的总位数n与一个无符号整数的二进制位数(即这台计算机的字长)相等,完成这些次循环右移后的结果将于x完全一样,因此我们就不必对x进行循环右移了。如果n小于这台计算机的字长,那我们就必须把x循环右移n位,如果n大于这台计算机的字长,那么我们只需利用取模运算求出n对这台计算机字长的余数,再把x循环右移这个余数所代表的次数。基于上述分析,我们得出了一个无需使用循环语句的解决方案。
~0 << n
:把一个全1的屏蔽码左移n为,在它最右端制造n位0。
~(~0 << n)
: 把这个屏蔽码最右端的n位设置为1,其余位设置为0。
当我们用这个屏蔽码和x进行与运算是,x的最右端n位将被赋值给变量rbits,然后将rbits中的1左移到它的最左端,把x右移n位,再对右移后的x和rbits进行或运算就完成了。
unsigned rightrot(unsigned x, int n)
{
int len = wordlength();
unsigned rbits;
if((n == n % len) > 0) {
rbits = ~(~0 << n) & x;
rbits = rbits << (len - n);
x = x >> n;
x = x | rbits;
}
return x;
}