Java千问:Java位运算经典应用(二)

接上篇

三、不借助中间变量交换两个变量的值

通常情况下,我们要交换两个变量的值都按如下步骤操作:


这种操作方式不难理解,实现交换变量值的关键点就在于中间变量c。而现在的题目要求是不借助中间变量来交换a和b的值。如果不使用位运算的方式,同样可以做到不借助中间变量交换两个变量的值,其实现过程如下。


为了讲解方便,我们把最初a与b的值称之为原始a和原始b,3行代码就是3步操作:
第1步:把原始a与原始b相加的和存储到变量a中,变量b的值暂时没有发生变化。
第2步:用这个和减去原始b,再赋值到变量b中,经过这一步运算,变量b中就保存了原始a的值。
第3步:用原始a、b之和减去原始a的值,就得到原始b,并且把这个值保存到变量a中。
通过以上3步就实现了a、b两个变量在不借助中间变量的情况下进行值的交换。这种算法虽然没有借助中间变量,但有一个问题是如果a和b都是较大的数,在做第1步操作的时候就有可能出现两值相加的和超出int类型的最大值,产生溢出的现象,从而导致后面的运算全部出错。
而我们用位运算的方式实现交换,就不存在这个问题了。具体代码如下:


讲述这段代码之前,先回顾一个运算规律,那就是:a^b^b的运算结果等于a。对此运算规律有疑义,请阅读《Java千问:Java语言位运算符详解》一文。为了表述方便,我们把a^b的操作称之为”用b对a加密”,之所以这么称呼,就是因为a与b进行了异或运算之后,得到一个全新的值,效果如同对a加密一样。而把a^b^b的操作称之为”还原”, 之所以这么称呼,就是因为a^b^b的运算结果等于a,如同是把a的值”加密”之后,又进行了还原,恢复了a的值。
我们还是把a和b最初的值称为原始a和原始b。这三行代码是如何实现变量值交换的呢?我们逐行讲解:
第1行代码:对a用b进行了加密操作,并且又赋值给了变量a,此时变量a就由原始数据变成了加密后的值。
第2行代码:把加密后的值与原始b进行异或运算,就还原了原始a的值,我们把这个值赋值给b,这样变量b中就存储了原始a的值。
第3行代码:用加密后的值与现在的b,也就是保存了原始a的变量进行异或操作,就能得到原始b的值,之后再把原始b的值赋值给变量a,这样就完成了变量a与b值的交换。

四、找出单身狗元素

所谓找出单身狗元素就是指:一个数组中,某个数只出现了一次,而其他数都出现了两次,要求编写程序把那个只出现了一次的数找出来。完成这个题目的最核心原理就是: 两个相同的数字进行异或运算,结果为0,而任何一个整数与0进行异或运算,其结果都是这个数本身。另外,任意N个整数进行异或操作,满足交换律
按照这个思路,我们只需要把数组中所有的元素都做一遍异或操作,所得到的值就是那个只出现了一次的数字。因为出现了两次的数字,它们之间进行异或操作会变为0。即使这两个数字没有挨在一起,但根据异或运算的交换律我们可以知道:位置关系并不影响运算结果,所以两个相同的数字只要都参与了异或运算,最终的结果都是0。而那个只出现了一次的数字,与0进行异或操作,其结果仍然是它自身的值。因此,异或运算的结果就是那个只出现了一次的数字,我们根据异或运算的结果,就能找出”单身狗”元素了。具体实现代码如下:


这道题目还有另一个版本,题目描述为:有整型数组a和b,a数组中所有元素都出现在b数组中,但b数组比a数组多出一个元素,编写程序找到b数组中多出来的这个元素。虽然变成了两个数组,但实现算法的思路并没有发生变化,只是由原来的一个数组全部元素参与异或运算,变成了两个数组中的元素都要参与异或运算,其实现代码如下:

(未完待续...)
如想系统学习Java编程,欢迎观看我在本站的视频课程。

原文地址:https://blog.51cto.com/2266836/2471727

时间: 2024-10-30 21:22:33

Java千问:Java位运算经典应用(二)的相关文章

Java千问:Java位运算经典应用(一)

很多人认为位运算在实际开发过程中并没什么用,学习位运算也只是为了应付面试.这种想法是错误的,接下来我们就通过几篇连载文章介绍一下位运算在实际开发过程中的几个经典应用实例.如果对位运算规则掌握还不是很熟练,可以先阅读<Java千问:Java语言位运算符详解>.这篇文章不仅详细讲解了Java位运算的基本规则和一些常用的运算定律,同时还在文中提到了一些常用的位运算实际应用,比如可以用位运算操作的方式快速把某个变量所在的内存单元清零,或者位运算的方式实现某个变量快速倍增等等.但文中所这提到的这几个实际

Java千问:Java语言中最大的整数再加1等于多少?

已知Java语言中int类型所能表示的最大整数为2147483647,请问以下代码执行结果是什么?一部分人都会认为这段程序压根就无法通过编译,也有人认为,这段程序能够通过编译,但在运行时会抛出异常,但更多的人面对这道题目根本就无从下手.那么正确答案是什么呢?首先告诉大家,这段程序能够顺利通过编译,并且在运行时也不会出现异常,运行的结果是在控制台上输出了数字-2147483648!而-2147483648正好是Java语言中int类型所能表示的最小整数.这个运行结果可能会让很多人感到大跌眼镜,运行

Java千问:关于Java语言复合赋值运算符的两个问题,快来瞧瞧!

我们知道,在Java以及很多高级编程语言当中,都有一种运算符叫做复合赋值运算符.复合赋值运算符由两个符号组成,它所能完成的运算操作也分为两步:第一步是运算,第二步是赋值.比如说:上面的这两条语句相当于但是,如果碰到下面这样的情况,a的值该应该是多少呢?有人认为应该按以下方式来计算,因为我们都知道,在四则运算规则中,遵循"先乘除,后加减"的原则按照这样的方式来计算,得到a的值应该是7,但实际运行程序所得到的结果是8.这是为什么呢?就是因为复合赋值运算符在完成运算的时候,遵循一个规则:把&

Java基本数据类型与位运算

Java基本数据类型与位运算 >>赋值运算符 赋值使用操作符“=”.它的意思是“取右边的值(即右值),把它复制给左边(即左值)”.右值可以是任何 常数.变量或者表达式 (只要它能 生成 一个值就行).但左值必须是一个明确的,已命名的变量.也就是说,必须有一个物理空间可以存储等号右边的值.分类 基本数据类型 与 类数据类型 的不同1. 对基本数据类型的赋值是很简单的.基本数据存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方.2. 但是在为

java加密解密算法位运算

一.实例说明 本实例通过位运算的异或运算符 “ ^ ” 把字符串与一个指定的值进行异或运算,从而改变每个字符串中字符的值,这样就可以得到一个加密后的字符串.当把加密后的字符串作为程序输入内容,异或运算会把加密后的字符串还原为原有字符串的值.效果图如下: 二.实现过程 1 package com.itxxz; 2 3 import java.util.Scanner; 4 5 /** 6 * java加密解密算法 7 * 8 * @author 螃蟹 9 * 网站:IT学习者 10 * 网址:ht

《Java千问》系列短文写作计划

大家好,我在51CTO开博客啦!我本人从事软件开发和教学多年,在我从事教学过程中,回答过很多学生的问题,但非常遗憾,我只是当场回答了这些问题,但事后并没有把这些问题的解答写成博客.我打算弥补一下这个缺憾,因此产生了写文章解答问题的想法.经过几天酝酿,我打算把这些文章写成系列短文,名字就叫<Java千问系列>.取这个名字并不是说真的有一千个问题,"千"只是表示多的意思.只要我有把握回答的,都发表出来.关于<Java千问系列>的文章,在这里我想做几点说明:一.<

Java位运算经典实例

一 源码.反码.补码 正数的源码.反码.补码相同,例如5:            5的源码:101            5的反码:101            5的补码:101 负数的源码.反码.补码不同,例如-5:            -5的源码:10000101            -5的反码:111111010 (取反操作)            -5的补码:111111011 (补码加1操作) 计算机所有数据都以补码存储和运算. 二 位操作       位操作包含&,|,!分别表示

Java千问:Java语言位运算符详解

很多编程语言都有位运算符,Java语言也不例外.在Java语言中,提供了7种位运算符,分别是按位与(&).按位或(|).按位异或(^).取反(~).左移(<<).带符号右移(>>)和无符号右移(>>>).这些运算符当中,仅有~是单目运算符,其他运算符均为双目运算符.在讲解这些运算符的使用之前,必须了解一个常识,那就是:位运算符是对long.int.short.byte和char这5种类型的数据进行运算的,我们不能对double.float和boolean进

Java笔记1(位运算)

1.位运算:| 操作符使用public class WeiHuoTest{       public static void main(String[] args){               int number1 = 10;              int number2 = 8;  /*    number1: 10    0000 0000 0000 0000 0000 0000 0000 1010    number2: 8    0000 0000 0000 0000 0000