目录
一、位运算符
二、位运算简单使用
1.判断奇偶数(与):
2.交换两个整数变量的值(异或):
三、做一道题:
题目:
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其他均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助空间,能否设计一个算法实现?
思路:
平时工作中,几乎没有使用过位运算,但今天详细了解了一下,发现这玩意实在是在方便了!!!
希望以后工作中能够合理地使用位运算!!!
一、位运算符
- &(与) ---- 操作符两边的值都为1时,结果为1;
- |(或) ---- 操作符两边的值有一个为1,结果为1;
- ^(异或) ---- 二进制数相同的位比较时,二者不同,结果为1;二者相同,结果为0;
- ~(取反) ---- 若操作数左边为1,则结果为0;操作数左边为0,则结果为1;
- >>(右移)和<<(左移) ---- 将二进制位进行右移或左移操作
- >>> ---- 与>>不同,该运算符是使用0填充高位
还要说明的就是,位运算满足交换律、结合律!!!
二、位运算简单使用
1.判断奇偶数(与):
我们都知道,在将十进制转换为二进制的过程中,就是不断地将值除2取余数的过程,直到余数为 0 或 1 ,然后将所有的余数从后往前串起来,就成了二进制的值。那也就是,二进制中偶数的最后一位是0,奇数的最后一位是1。利用这个特性,就很方便的使用 & 运算符来判断奇偶性了!!!
//使用位运算判断奇偶数
System.out.println(1&1); //1
System.out.println(2&1); //0
System.out.println(3&1); //1
System.out.println(4&1); //0
想起以前用 if else 来判断奇偶性,老脸一红!!!
2.交换两个整数变量的值(异或):
首先画张图来理解异或运算的过程:
根据上图,我们也可以推导出: a ^ a = 0, b ^ b = 0;
进而,a ^ b ^ a
a ^ b ^ b
也就是说,一个数与另一个数异或两次,值不变;
然后编写如下代码:
line1: int c = 13;
line2: int d = 31;
line3: c = c ^ d;
line4: d = c ^ d;
line5: c = c ^ d;
我们可以将 line3 与 line4 的代码结合起来,结果如下:
d = c ^ d ^ d
显然,d ^ d = 0,也就是现在已经是 d = c 了。
同理,line5 的代码可以转换为 :
c = c ^ d ^ c ^ d ^ d
去掉重复的 c 和 d,就只剩下 c = d了。
上面的两段代码中, = 右边的 c 和 d均为最初的 c 和 d的值!!!
三、做一道题:
题目:
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其他均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助空间,能否设计一个算法实现?
思路:
刚刚学习了异或运算,我们都直到,两个相同的数做异或运算,结果为0;
在这道题中,重复的那个数出现2次,其他的所有数都出现了1次,最终我们要做的就是将其他的数都消除掉,只剩下重复的数,那么该如何实现呢?
如果在当前数组中,重复出现的数值出现奇数次,而其他的不重复出现的数值都出现偶数次,再将所有的值做异或操作,是不是就可以了呢? 看下图:
如果我们将上图中的所有值做一个连续的异或,那么,除了重复值k,其他的数字都出现了2次,k出现了3次,这样,我们就消除掉了找出了重复的k值!!!有了思路,试着代码实现一下:
//先构造题目中的数组
int N = 1001;
int[] arr = new int[N];
//数组中的最后一位暂不赋值,用来存放重复的数值
for (int i=0; i<arr.length-1; i++){
arr[i] = i+1;
}
//随机选出一个重复的数并放在数组的最后一位
arr[N-1] = new Random().nextInt(N-1) + 1;
//随机找一个下标
int index = new Random().nextInt(N);
//将数组最后一个索引的重复值与随机下表的值交换
int temp = arr[N-1];
arr[N-1] = arr[index];
arr[index] = temp;
System.out.println(Arrays.toString(arr));
//解决办法
int n = 0;
//首先先将1 至 1000所有不重复的数做异或运算
for (int i=0; i<=N-1; i++){
n = n ^ i;
}
//将上面的结果与数组中的所有元素做异或运算
for (int i=0; i<N; i++){
n = n ^ arr[i];
}
System.out.println(n);
其实解题代码不多,只有后面的两个for循环,前面的代码是用来构建符合题目的数组!
我将N设置为5,试了好多次,目测是正确的!!!