异或运算及其应用

异或是一种基于二进制的位运算,用符号XOR或者 ^ 表示,

其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1。

它与布尔运算的区别在于,当运算符两侧均为1时,布尔运算的结果为1,异或运算的结果为0。

一、异或的性质

  1. 交换律:a ^ b = b ^ a
  2. 结合律:a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
  3. d = a ^ b ^ c 可以推出 a = d ^ b ^ c
  4. 自反性:a ^ b ^ a = b

 

二、异或的应用

  1. 交换两个数

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

 

************************************************************************************************************************

  1. 找出重复的两个数

题目:

        现有 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);
	}
	
}

可以看出,方案三是最佳解决方案,效率高和资源消耗小。

异或运算在现实编程过程中使用不是很多,因此很多人会忽略此种方法。但是此种方法是一种很好的方法。所以在以后的学习过程中要多多总结,可能会得到意想不到的结果。

 

转载于:https://my.oschina.net/AaronDMC/blog/818979

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值