《算法心得》一点整理

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

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

时间: 2024-10-17 16:40:23

《算法心得》一点整理的相关文章

关于Java IO InputStream 的一点整理!

程序的开发当中一直在用文件的读写,但是对于java当中输入流以及输出流只是会用不理解,一直以来想搞清楚其,但是一直没有执行(悲剧),今天早上抽出半个小时通过JDK API1.6.0中文版帮助逐步的了解下字节输入流读取字节的方法: 下面就说说InputStream当中read().read(byte[]  b).read(byte[] b.int off .int len)的使用以及区别 一.read()方法: public static void inputStreamRead1() { try

关于MyBatis sqlSession的一点整理

原文地址:关于MyBatis sqlSession的一点整理 工作中,需要学习一下MyBatis sqlSession的产生过程,翻看了mybatis-spring的源码,阅读了一些mybatis的相关doc,对mybatis sqlSession有了一些认知和理解,这里简单的总结和整理一下. 首先, 通过翻阅源码,我们来整理一下mybatis进行持久化操作时重要的几个类: SqlSessionFactoryBuilder:build方法创建SqlSessionFactory实例. SqlSes

关于单链表反转的一点整理

单链表的反转困扰了我好几天了.今天终于一通百通了,特地记录一下,免得以后又忘记了.脑子笨,只能靠这种办法了. 之前网上的一种做法是这样的: 1 public void reversList(){ 2 Node pre = null; 3 Node next = null; 4 while (head != null) { 5 next = head.next; 6 head.next = pre; 7 pre = head; 8 head = next; 9 } 10 head = pre; 1

Linux 下安装MySql的一点整理

一.安装步骤: 1.去mysql官网下两个RPM安装包.客户端(如:MySQL-client-5.5.43-1.linux2.6.i386.rpm)与服务器端(如MySQL-server-5.5.43-1.linux2.6.i386.rpm) 2. 在Linux系统上敲下如下命令: rpm -qa | grep mysql 以此检测系统是否有安装mysql的关联软件.有关联软件的,一定要删除掉.否则就会出现这种情况:   3.验证mysql是否正确装好的方法: 输入 netstat -nat  

一点整理

多态,从希腊语言的理念而来, c++支持单继承的同时同样支持多继承.而Java仅保留了单继承,多继承由接口实现.  virtual这一关键字,体现一种公享,避免了信息的冗余.而且,体现一种c++面向对象的一种机制. 从理论到底层实现,虽然有不安全的体现. #include"sts.h" #if(0) #endif #if(0) class B   {    virtual void vfun(int i = 10);   }; class D : public B   {    vir

Mysql一些重要配置参数的学习与整理(三)?

原文地址:Mysql一些重要配置参数的学习与整理(三) 之前的Mysql一些重要配置参数的学习与整理(一)和Mysql一些重要配置参数的学习与整理(二)中,对于线上mysql服务器的一些配置参数进行了学习,不过参阅官方doc后对其中的一些参数的配置的理解不是很清晰,今天与同事进行了交流和沟通,都一些重要的配置交换了意见,本篇就对其中的一些疑问点,整理一下心得.     skip-external-locking作用     在Mysql Linux 的发行版中,默认存在一行skip-extern

关于编程,新手最容易问的一些问题!

以下都是一些新手经常会问到的问题,兄弟连PHP培训 小编做了一点整理,帮你解决问题! 1.问:C语言.BASIC语言.PASCAL语言等等到底学哪一种好? 答:对初学者来说,学哪一种都无所谓,我觉得关键是要学到编程的理念,当你真正体会到编程是怎么一回事的时候,你会发现无论哪种语言都能编出好软件. 2.问:学XX语言有钱途吗? 答:很明白的告诉你,最有钱途的就是抢银行.贩毒. 3.问:XX语言难学吗? 答:"难"其实是相对而言的,难只会出现在不肯用功的人身上. 4.问:怎样才能学好编程?

matrix calculator

2.1 Matrix derivative //这一节上的已经凌乱了……一点一点整理吧 首先,明确几个概念. 方向导数&梯度(滚混去看高数吧书上都有你上学期到底学了些屎) 定义就不说了,通俗的来说,方向导数是给定一个角度(或者一个单位向量e 表示为(cos a,cos b)a+b=pi/2)或者说方向,函数在该方向的导数.其值为函数在某方向的函数变化率,即单位长度下函数的改变量.可以使任意方向,所以一个函数上的一点有无数个方向导数. 梯度指的是方向导数中函数变化率最大的方向所对应的向量.其值为基

假期七天实习参观有感

假期实习参观七天有感 1月16日 第二届全国大学生创业实战大赛全国总结 过了这个假期,我们即将步入大学三年级下学期,距离毕业只有不到短短一年半的时间了,这个假期,系里经过讨论交给我们这届大三生一个外出参观实习一周的安排任务.1月16日,我和同系的杨航,何玥还有李晨曦组成一个小组,一起外出参观学习.16日这天,经过我们的多方查找,第二届全国大学生创业实战大赛总结赛在北大博雅酒店开展,我们四个人报了名去比赛现场观赛. 全国大学生创业实战大赛由欧美同学会企业家联谊会.中国投资创业协会指导,校导网主办,