码迷,mamicode.com
首页 > 其他好文 > 详细

《算法心得》一点整理

时间:2014-06-14 14:07:25      阅读:270      评论:0      收藏:0      [点我收藏+]

标签:算法

最近在图书馆看到本神书《算法心得:高效算法的奥秘》,主要讲解计算机算法的,强调编译器优化和计算机体系结构设计的。虽然看的不大懂,但还是给自己增长了见识和知识。少许整理些自己感兴趣的算法,以备后续温故知新。

1. 操作最右边的位元
a. 将字组中值为1且最靠右的位元置0,如果不存在值为1的位元,则全部结果为0(例如 0101 1110 => 0101 1100):
x & (x-1)
这个操作可以判断无符号证书是不是2的幂或者0.

b. 将字组中值为0且最靠右的位元置1,如果不存在值为0的位元,则全部结果的每一位为1(例如 1010 0111 => 1010 1111):
x | (x+1)
这个操作可以判断无符号证书是不是2的幂或者0.

c. 将字组尾部的1全部变成0,如果尾部没有1,则不变(例如 1010 0111 => 1010 0000)
x & (x+1)
这个操作可以判断无符号证书是不是2^n-1或者0.

d. 将字组尾部的0全部变成1,如果尾部没有0,则不变(例如 1010 1000 => 1010 1111)
x | (x-1)

e. 将字组中值为0且最靠右的位元置1,其余位置0,如果不存在值为0的位元,则全部结果的每一位为0(例如 1010 0111 => 0000 1000):
~x & (x+1)

f. 将字组中值为1且最靠右的位元置0,其余位置1,如果不存在值为1的位元,则全部结果的每一位为1(例如 1010 1000 => 1111 0111):
~x | (x-1)

g. 将字尾部所有0的位元变成1,其余位置0,如果不存在值为0的位元,则全部结果的每一位为0(例如 0101 1000 => 0000 0111):
~x & (x-1) 或 ~(x | -x)

h. 将字尾部所有1的位元变成0,其余位置1,如果不存在值为1的位元,则全部结果的每一位为1(例如 1010 0111 => 1111 1000):
~x | (x+1)

i. 将字组中值为1且最靠右的位元保留,其余位置0,如果不存在值为1的位元,则全部结果的每一位为0(例如 0101  1000 => 0000 1000):
x & (-x)

j. 将字组中值为1且最靠右的位元,以及其右方所有值为0的位元都置为1,其余位置0,如果不存在值为1的位元,则全部结果的每一位为1,而当x尾部没有值为0的位元是,运算结果是1(例如 0101  1000 => 0000 1111):
x ^ (x-1)

k. 将字组中值为0且最靠右的位元,以及其右方所有值为1的位元都置为1,其余位置0,如果不存在值为0的位元,则全部结果的每一位为1,而当x尾部没有值为0的位元是,运算结果是1(例如 0101  0111 => 0000 1111):
x ^ (x+1)

l. 将字组右侧连续出现且值为1的位元置为0,(例如 0101 1100 => 0100 0000):
( ( x | (x-1)) +1 ) & x

m. 将字组右侧连续出现且值为0的位元置为1,(例如 0100 0111 => 0111 1111):
( ( x & (x+1)) -1 ) | x

根据上面的知识规律,下面这道题就可以这样做:
例如:求给定数 x 往上增加最近的2^n 的值。如给定5时,求出8,给定4时,求出4.
unsigned int fun1(unsigned int x)
{
x = x<<1;
while ( x & (x-1) )
     x = x & (x-1);
return x; 
}

unsigned int fun2(unsigned int x)
{
while ( ( ( x | (x-1) ) +1 ) & x )
     x = ( ( x | (x-1) ) +1 ) & x ;
return x<<1;
}

2. 德摩根定律
~(x&y) = ~x | ~y
~(x|y) = ~x & ~y
~(x+y) = ~x - y
~(x-y) = ~x + y
~-x = x-1

3. 位操作新式用法
给定一个数x,然后找出下一个比它大的数字y,该数字y中值为1的位元数与x中的相同。这题可以用在找出元素个数为某一定值的全部子集的算法中。
思路:给定一个表示子集位串的字组x,首先要找到连续出现在x右侧且值为1的一组位元,然后将该值“加1”,再把原来后面跟着的哪些0 补上。举例来说,如果带计算的位串是xxx0 1111 0000,那么结果就应该是xxx1 0000 0111,其中xxx这三个位元值不限。该算法首先定义 s = x&-x,算出s == 0000 0001 0000,这样就找到x中最小的那个1。然后把它与x相加,把两书只和xxx1 0000 0000存放在r 中。此时结果中的1个位元已经计算好了,想求出其他位元,还需要把位串中剩下的n-1个“1”移到右侧。要向移动到右侧,首次要计算r和x的异或,在本例中就是0001 1111 0000.
上面那个值中“1”的个数太多了,而且没有靠右对齐。为了解决此问题,要将它与s相除,这样就可以把哪些“1”靠右对齐了,除之前还要先向右移动2位,以便丢弃那2个多余的位元。此结果与r取或,就得到最终答案了。
用C语言实现就是
unsigned fun3(insigned x)
{
unsigned smallest, ripple, ones;
                               //x=xxx0 1111 0000
smallest = x & -x;             //  xxx0 0001 0000
ripple = x +smallest;          //  xxx1 0000 0000
ones = x ^ ripple;             //  xxx1 1111 0000
ones = ( ones>>2 )/smallest;   //  xxx0 0000 0111
return ripple | ones;          //  xxx1 0000 0111
}

4. 结合逻辑操作的加减运算
-x = ~x+1
-~x = x+1
~-x = x-1
x^y = ( x|y ) - ( x&y )
x + y = ( x^y ) + 2( x&y )
         = ( x|y ) + ( x&y )
x - y  = ( x^y ) - 2( ~x&y )
         = ( x&~y ) - ( ~x&y )
其中 x + y = ( x^y ) + 2( x&y ) 是先对两数做不进位加法x^y,然后再补上进位。
x - y  = ( x^y ) - 2( ~x&y ) 是先对两数进行不进位剪发x^y,然后再把结尾的位从结果中减去。

5. 与常数相乘
要将x乘以13(二进制1101),可执行下述操作
t1 = x<<2;
t2 = x<<3;
r = x + t1 + t2;

《算法心得》一点整理,布布扣,bubuko.com

《算法心得》一点整理

标签:算法

原文地址:http://blog.csdn.net/huaxi1902/article/details/30728381

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!