接上篇
五、字符串加密
在很多场合下,都需要给字符串进行加密,使字符串由”明文”变成”密文”。对字符串加密有很多种算法,其实我们利用位运算也可以实现简单的加密效果。用位运算实现加密的原理很简单,这里为大家讲解一下。假设有两个整数a和b,a^b的结果为c。我们可以认为a就是原始数据,a与b进行异或运算所得到的c就是加密后的数据,b在加密过程中扮演着”密钥”的角色。在不知道b值的情况下,如果只是知道c的值,任何人无法仅仅根据c的值反推出a的值,也就是说,如果我们只知道加密后的数据,而不知道密钥,根本无法确切得知原始数据a的值到底是多少。如果想根据加密后的数据c来还原初始数据a,就必须用密钥b来解密。解密的方法也很简单,只要进行c^b的操作就可以了。其原理就是”a^b^b=a”,在这个等式中,”a^b”的结果就是c,所以”c^b=a”。
理解了加密和解密的最基本原理之后,我们再来说说如何具体对字符串实施加密操作。我们知道,位运算符只能对byte、short、int、long和char这几种基础类型的数据进行运算,对字符串这种引用类型的数据并不适用。既然字符串无法进行位运算,那么该如何对字符串进行加密呢?我们知道,无论是图片还是文本,在计算机当中都是以二进制数的形式进行存储的。既然是二进制数,那么每8位的二进制数,都可以转换成一个byte类型的数据。而N个8位二进制,就可以转换成一个byte数组。概括成一句话就是:任何形式的信息,在计算机当中都可以用byte数组来存储和表示。
我们现在要对字符串进行加密,表示字符串的String类提供了一个叫做getBytes的方法,这个方法可以把字符串转换成一个byte数组。我们让数组中的每一个元素都与某个数key进行异或运算,就能得到一个全新的byte数组,这个全新的byte数组本质上就是加密后的字符串,而那个数字key,其实就是加密过程中的”密钥”,如果我们想要还原字符串,根据之前讲过的”c^b=a”这个等式,我们可以再次用key这个数字与那个全新的byte数组的每一个元素做一次异或运算就可以。字符串加密的完整代码如下:
如果密钥key的值为111,程序运行效果如下图
如果密钥key的值为121,程序运行效果如下图
六、计算一个二进制数当中1的个数
我们知道,一个二进制数,每个位上只能有0和1这两种情况。如果我们想计算出一个N位的二进制数,总共有多少个位上是1,该如何计算呢?我们可以把这个二进制数进行右移1位,然后再左移1位,如果经过两次位移运算,这个二进制数仍然保持不变,那么说明这个二进制数的最低位(也就是最右边那1位)上的数字为0,否则说明最低位为1。有的小伙伴可能没有弄明白这个原理,我们以一个8位的二进制数”00000101”作为例子来说明。我们把该二进制数称为a。我们可以看到:a的最低位为1。如果a右移1位,将得到” 00000010”,然后再把” 00000010”左移1位,按照”左移操作最右边补0”的运算规则,可以得到运算结果为” 00000100”,我们把这个运算结果称为b。可以看出,a与b并不相等。然而,假如a的值为” 00000100”的话,也就是说,a的最低位为0,那么经过一次”右移再左移”,所得到的运算结果b仍然是” 00000100”。因此,一个二进制数经过一次”右移再左移”的操作,如果仍然能够和原来的值相同,那么说明这个二进制数的最低位为0,否则最低位为1。
现在的题目要求我们计算一个二进制数的各位总共有多少个1,而以上算法仅能判断最低位是否为1,那么应该怎样把一个二进制数上所有的1都统计一遍呢?还拿刚才举例所用的二进制数a来讲解。我们可以首先定义一个计数器,命名为count,并设count的初始值为0。当我们把a进行一次”右移再左移”的操作之后,发现原始数字a和运算结果b并不相同,这说明a的最低位是1,而我们要做的事情正是计算a当中总共有多少个位上是1,于是我们就可以把计数器count加1。之后,我们再把a做一次无符号右移并赋值给a自身。这里有两个需要注意的细节。首先,无符号右移结束之后,有一个非常关键的操作”赋值给a自身”,这使得a会被重新赋值,从而a的值就变成了”00000010”。其次,我们对a进行赋值之前进行的那个右移操作是”无符号右移”,也就是给a的最左边补的数是0。如果我们不断的重复这个过程,直到a的值变为”00000000”才停下来。在这个过程中,每次遇到最低位为1的情况,就使计数器count的值加1。当运算彻底停止之后,通过count的值就可以得知a的各个位总共有多少个1。计算二进制数中各个位总共有多少个1的完整代码如下:
(未完待续...)
如果想系统学习Java编程可以点击这里观看我在本站的视频课程。