一、判断整数的奇偶性
传统思路:
按照传统的思路,判断一个整数的奇偶性是通过用这个数与2求模,看运算结果是否为0
位运算思路:
Java语言中,所有数字存储在内存中,都要先转换成补码的形式。任何一个偶数用补码表示出来后,它的最后一个二进制位都是0,而奇数补码的最后一个二进制位都是1。所以,我们可以通过判断这个整数的补码的最后一位二进制数是0还是1,来判断这个数是偶数还是奇数。判断的方法就是用这个数与1进行按位与的操作,如果结果为0,那么这个数就是偶数,否则就是奇数。
/**
* 判断整数的奇偶, true表示偶数,false表示奇数
*/
public static boolean judgeParity(int x){
return (x & 1) == 0;
}
二、求绝对值
传统思路:
首先判断一个数a是否>=0,如果a>=0,则返回a本身,否则返回a的相反数
位运算思路:
任何一个整数与0进行异或运算后依然保持不变
任何一个整数与-1进行异或运算后再加上1,得到的结果就是这个数的相反数
数字-1用补码的形式表示出来,恰好是一个32位全为1的二进制串。这个二进制串与任何一个其他二进制串进行按位异或运算,都可以达到”取反”的效果,一个正数按位取反后再加1,得到的就是它相反数
int类型的正数经过带符号右移31位之后,得到的必然是0,而负数经过带符号右移31位得到的是-1。我们就可以通过右移所得到的这个0或者-1,判断出这个数是正数还是负数
/**
* 获取绝对值
* int类型的正数经过带符号右移31位之后,得到的必然是0,而负数经过带符号右移31位得到的是-1。我们就可以通过右移所得到的这个0或者-1,判断出这个数是正数还是负数
* 1.任何一个整数与0进行异或运算后依然保持不变
* 2.任何一个整数与-1进行异或运算后再加上1,得到的结果就是这个数的相反数
*/
public static int abs(int x){
int i = x >> 31;//如果x为整数,则i为0,为负数i为-1
return (x ^ i) - i;
}
三、变量交换两个变量的值
传统思路:
借助中间变量来实现
位运算思路:
abb的运算结果等于a
/**
* 交换变量值
* a^b^b的运算结果等于a
*
* @param a
* @param b
*/
public static void exchange(int a, int b){
a = a ^ b;//g = x ^ y
b = a ^ b;//h = g ^ y = x ^ y ^ y = x 还原了a的值,赋值给b
a = a ^ b;//j = g ^ h = x ^ y ^ x
System.out.println("交换结果:a=" + a + " b=" + b);
}
四、找出数组中只出现一次的元素
传统思路:方式有很多,我们随便写一种
//利用HashSetkey元素不重复的特性
HashSet<Integer> set = new HashSet<Integer>();
for (int i : array) {
//如果存在,则删除
if(!set.add(i)){
set.remove(i);
}
}
//最后剩下不重复的元素
System.out.println("=======" + set.toString());
位运算思路:
两个相同的数字进行异或运算,结果为0,而任何一个整数与0进行异或运算,其结果都是这个数本身。另外,任意N个整数进行异或操作,满足交换律。
具体实现如下:
/**
* 位运算放方法 限定数组中只有一个只出现一次的元素
* 思路:两个相同的数字进行异或运算,结果为0,而任何一个整数与0进行异或运算,其结果都是这个数本身。另外,任意N个整数进行异或操作,满足交换律。
* @param array
*/
public static void queryOnceBit(int[] array){
int find = 0;
for(int x: array){
find = find ^ x;
}
System.out.println("只出现一次的元素" + find);
}
/**
* 有整型数组a和b,a数组中所有元素都出现在b数组中,但b数组比a数组多出一个元素
* 思路:两个相同的数字进行异或运算,结果为0,而任何一个整数与0进行异或运算,其结果都是这个数本身。另外,任意N个整数进行异或操作,满足交换律。
*
*/
public static void queryOnceBit(int[] arrayA, int[] arrayB){
// int[] arrayA = {1, 5, 6};
// int[] arrayB = {5, 1, 8, 6};
int find = 0;
for(int i = 0; i < arrayA.length; i++){
find = find ^ arrayA[i] ^ arrayB[i];
//0^1^5^5^1^6^8 = 6^8
}
//6^8^6 = 8
find = find ^ arrayB[arrayB.length - 1];
System.out.println("只出现一次的元素" + find);
}
五、字符串加密
假设有两个整数a和b ,a^b的结果为c。我们可以认为a就是原始数据,a与b进行异或运算所得到的c就是加密后的数据,b在加密过程中扮演着”密钥”的角色。
基础:无论是图片还是文本,在计算机当中都是以二进制数的形式进行存储的。既然是二进制数,那么每8位的二进制数,都可以转换成一个byte类型的数据。而N个8位二进制,就可以转换成一个byte数组。概括成一句话就是:任何形式的信息,在计算机当中都可以用byte数组来存储和表示。
/**
* 原理:a^b^b = a
* @param text
* @param key
*/
public static void encoder(String text, byte key){
byte[] bytes = text.getBytes();
byte[] tranCodes = new byte[bytes.length];//用于保存每个加密后的字节
// byte[] keyBytes = key.getBytes();//密钥
System.out.println("原始字符串为:"+ text);
//加密过程
for (int i = 0; i < bytes.length; i++) {
tranCodes[i] = (byte)(bytes[i] ^ key);// 对每个字节进行加密
}
String encode = new String(tranCodes);//用加密后的字节数组创建字符串
System.out.println("加密后的字符串:"+encode);//输出加密后的字符串
//解密过程
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte)(tranCodes[i] ^ key);//对每个字节完成解密
}
String decode = new String(bytes);
System.out.println("解密后的字符串:"+decode);//输出解密后的字符串
}
六、计算一个二进制数当中1的个数
二进制数进行右移1位,然后再左移1位,如果经过两次位移运算,这个二进制数仍然保持不变,那么说明这个二进制数的最低位(也就是最右边那1位)上的数字为0,否则说明最低位为1。
00000101 右移一位 00000010
00000010 左移一位 00000100
操作之后不相等,则说明最后一位是1,相等则为0
无符号右移,左边填0,那么不断的无符号右移,当为00000000时则全部计算完毕
/**
* 计算输入int的二进制1的个数
* @param x
* @return
*/
public static int count1(int x){
int count=0;
while(x!=0) {
if((x>>1)<<1 != x) //对a进行"右移再左移",判断其结果是否等于原来的a
{
++count;
}
x = x>>>1;//完成1次判断,对a进行无符号右移并把运算结果赋值给a自身
}
return count;
}
其他应用遇到了再做更新。
参考:
网友评论