异或运算及其应用
2017-01-05 00:00
323 查看
异或是一种基于二进制的位运算,用符号XOR或者 ^ 表示,
其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1。
它与布尔运算的区别在于,当运算符两侧均为1时,布尔运算的结果为1,异或运算的结果为0。
结合律:a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
d = a ^ b ^ c 可以推出 a = d ^ b ^ c
自反性:a ^ b ^ a = b
测试结果如下:
交换前: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其中任意一个数(唯一重复的数字)。
问题:将这个重复数字找出来。
可以看出,方案三是最佳解决方案,效率高和资源消耗小。
异或运算在现实编程过程中使用不是很多,因此很多人会忽略此种方法。但是此种方法是一种很好的方法。所以在以后的学习过程中要多多总结,可能会得到意想不到的结果。
其运算法则是对运算符两侧数的每一个二进制位,同值取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); } }
可以看出,方案三是最佳解决方案,效率高和资源消耗小。
异或运算在现实编程过程中使用不是很多,因此很多人会忽略此种方法。但是此种方法是一种很好的方法。所以在以后的学习过程中要多多总结,可能会得到意想不到的结果。