数据结构
异或运算
num1 | num2 | num1^num2 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
-
异或运算:位运算的一种
-
相同为0 不同为1
-
可以理解为
无进位相加
-
异或满足交换律,结合律
-
1^ 2^ 3^ 4^ 5^ 5^ 4^ 3^ 2^ 1 = 1^ 1^ 2^ 2^ 3^ 3^ 4^ 4^ 5^ 5 = 0
1.交换位置
public static void swap(int[] arr, int i, int j) {
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
执行流程解析
a=2;b=3;
a = a ^ b; //a = 2 ^ 3;
b = a ^ b; // b = 2 ^ 3 ^3 = 2;
a = a ^ b; // a = 2 ^ 3 ^ 2 = 3;
- 这种交换的思想是异或运算(相同为0,不同为1)(1^ 2^ 1 = 2)
- 两个相同的数异或为0
- 0和任何数异或还得任意数
- 快且省空间,计算机毕竟看01更好些
- 注:
这里的交换两个元素的位置不能是同一个位置,i不能等于j
选择排序和冒泡排序都关系到元素的换位置
选择是先找要交换的下标,然后交换;
冒号是相邻比较交换,将大的数据换到后面去;
2.找出不成对的那个数(人生密码)
2.1 只有一种数出现了奇数次,其他的所有数都出现了偶数次,,,请找出出现奇数次的数值
#include<stdio.h>
int main() {
int n,ans=0,x;
while(scanf("%d",&n)&&n!=0)
{
ans=0;
if(n==1)
{
scanf("%d",&x);
printf("%d\n",x); //奇数个元素,如果是一个元素的话,就直接输出
}
else{
for(int i=0;i<n;i++) //如果是多个元素就做异或运算
{
scanf("%d",&x); //如果a=6,b=6 ,那么a^b的结果就是0(相同为0不同为1)
ans^=x; //如果a=0,b=5,那么a^b的结果就是5(0与任何数做异或运算还得任意数)
}
printf("%d\n",ans);
}
}
}
输入:
3 8 9 8
5 1 2 1 2 3
0
输出:
- 异或运算就像消消乐一样,遇到相同的数就归0 了
(相同为0,不同为1):是二进制按位运算
1^2=3;
1^3=2;
综上: 1^2 ^1 = 2;
1^ 2 ^ 3 ^ 2^ 5^ 1 = 5;
2.2 有两种出现奇数次的数,和多个出现偶数次的数,找出出现奇数次的那两个数值
public static void printOaaTimesNum(int[] arr) {
int eor = 0;
for (int i : arr) {
eor ^= i;
}
//eor = a ^ b;
//eor != 0;
//eor必然有一个位置上是1
int rightOne = eor & (~eor + 1); //提取出eor二进制最右边的1
int onlyOne = 0; //eor'
for (int i : arr) {
if ((i & rightOne) == 1){ //这里判断等于1或0都是一样的效果
onlyOne ^= i;
}
}
System.out.println(onlyOne+ " "+(eor ^ onlyOne));
}
- 一个数与上(自己取反+1)就是把自己最右边的第一不为0的数取出来