异或是一种基于二进制的位运算,用符号XOR或者 ^ 表示,
其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1。
它与布尔运算的区别在于,当运算符两侧均为1时,布尔运算的结果为1,异或运算的结果为0。
一、异或的性质
- 交换律:a ^ b = b ^ a
- 结合律:a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
- d = a ^ b ^ c 可以推出 a = d ^ b ^ c
- 自反性:a ^ b ^ a = b
二、异或的应用
-
交换两个数
package com.demo.algorithms;
public class NumSwitchDemo {
/**
* 交换两个数: 最常见的做法就是增加一个临时变量.
*
* @param a
* @param b
*/
public static void switchValue1(int a, int b) {
System.out.println("交换前:a:" + a + "\tb:" + b);
int temp = b;
b = a;
a = temp;
System.out.println("交换后:a:" + a + "\tb:" + b);
}
/**
* 交换两个数: 升级版,将两个数加减来实现.
*
* @param a
* @param b
*/
public static void switchValue2(int a, int b) {
System.out.println("交换前:a:" + a + "\tb:" + b);
a = a + b;
b = a - b;
a = a - b;
System.out.println("交换后:a:" + a + "\tb:" + b);
}
/**
* 交换两个数: 利用异或运算,也可以将两个数交换.
* @param a
* @param b
*/
public static void switchValue3(int a, int b) {
System.out.println("交换前:a:" + a + "\tb:" + b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("交换后:a:" + a + "\tb:" + b);
}
public static void main(String[] args) {
switchValue1(33, 77);
System.out.println("================================================");
switchValue2(22, 55);
System.out.println("================================================");
switchValue3(88, 99);
}
}
测试结果如下:
交换前:a:33 b:77
交换后:a:77 b:33
================================================
交换前:a:22 b:55
交换后:a:55 b:22
================================================
交换前:a:88 b:99
交换后:a:99 b:88
************************************************************************************************************************
-
找出重复的两个数
题目:
现有 0-99,共计100个整数,各不相同,将所有的数放入一个数组,随机排布。
数组长度101,多余的数字是0到99其中任意一个数(唯一重复的数字)。
问题:将这个重复数字找出来。
package com.dmc.demo;
/**
* Algorithms01
* 作者:Aaron
* 时间:2016年1月5日-下午9:00:20
* @version 1.0.0
*/
public class Algorithms01 {
/**
* 题目一:现有 0-99,共计100个整数,各不相同,将所有的数放入一个数组,随机排布。
* 数组长度101,多余的数字是0到99其中任意一个数(唯一重复的数字)。
* 问题:将这个重复数字找出来。
*/
/**
* 方案一:找出数组中的重复数字(双重循环)
* 缺点:效率太低
*
* 分析:
* 1、把数组构造出来;
* 2、把数组元素添加进去;
* 3、对数组的元素进行打乱(随机排布);
* 4、找重复元素。
*
* 包名:com.dmc.demo
* 方法名:findSameNum
* 作者:Aaron
* 时间:2017年1月5日-下午9:18:34
* @param num
* void
* @Exception
* @since 1.0.0
*/
public static void findSameNum(int num){
// 把数组构造出来
int[] arr = new int[101];
// 把数组元素添加进去
for(int i=0; i<100; i++){
arr[i] = i;
}
//将重复元素添加进去
arr[100] = num;
// 打乱前:遍历数组
for(int i=0; i<arr.length; i++){
System.out.print(arr[i]+"\t");
}
System.out.println();
// 将数组打乱
for(int i=0; i<10000; i++){
int index1 = (int)(Math.random()*101);
int index2 = (int)(Math.random()*101);
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
// 打乱后:遍历数组
for(int i=0; i<arr.length; i++){
System.out.print(arr[i]+"\t");
}
System.out.println();
// 找出重复元素
dmc:for(int i=0; i<arr.length; i++){
for(int j=i+1; j<arr.length; j++){
if(arr[i] == arr[j]){
System.out.println("重复数字为:"+arr[i]);
break dmc;
}
}
}
/**
* 方案二:找出数组中的重复数字
* 缺点:如果数据太大而且多就会有数据溢出
*
* 分析:
* 1、计算所有元素的和;
* 2、用所有元素的和减去1-99元素之和.
*/
int sum = 0;
// 求所有元素的和
for(int x=0; x<arr.length; x++){
sum += arr[x];
}
// 用sum减去0-99的和
for(int x=0; x<100; x++){
sum -= x;
}
System.out.println("重复元素是:" +sum);
/**
* 方案三:找出数组中的重复数字(异或算法解决)
*
* 分析:
* 回顾异或算法知识点:X^0^1^2^3^......^97^98^99^0^1^2^......^97^98^99 = X
* 那么:0^1^2^3^...^m^...^98^99^m^0^1^2^...^m^...^98^99 = m
*/
// 使用数组第一个元素异或后面的所有元素
for(int x=1; x<arr.length; x++){
arr[0] = arr[0] ^ arr[x];
}
// 再次把arr[0]保存的结果和0-99的数据异或一次
for(int x=0; x<100; x++){
arr[0] = arr[0] ^ x;
}
System.out.println("重复的数字是:"+arr[0]);
}
public static void main(String[] args) {
findSameNum(52);
}
}
可以看出,方案三是最佳解决方案,效率高和资源消耗小。
异或运算在现实编程过程中使用不是很多,因此很多人会忽略此种方法。但是此种方法是一种很好的方法。所以在以后的学习过程中要多多总结,可能会得到意想不到的结果。