1.首先先列一下所有的位运算符
1):按位与(&)
两个都位一才为1,例如5与8的与运算
0000 0101
&
0000 1000
——————
0000 0000
2): 按为或( | )
有1即为1,还是5与8的例子
0000 0101
|
0000 1000
——————
0000 1101
3):按位异或(^)
相同为0,不同为1,例子12 和 7
0000 1100
^
0000 0111
——————
0000 1011
4):按位取反( ~ )
略
5):左移运算<<(无符号左移<<<)
左移运算将数对应的二进位全部向左移动若干位,高位丢弃,低位补 0。左移运算的运算符为 <<。举个例子,将数字 5 左移 4 位,其实是将数字 5 对应的二进制 0000 0101 中的二进位向左移动 4 位
5 << 4
= 0000 0101 << 4
= 0101 0000 # 高位丢弃,低位补 0
= 80
=5*2的4次方
6)右移运算>> (无符号右移>>>,左边空缺补充为0)
右移运算将数对应的二进位全部向右移动若干位。对于左边的空位,如果是正数则补 0,负数可能补 0 或 1 (Turbo C 和很多编译器选择补 1)。右移运算的运算符为 >>。举个例子,将数字 80 右移 4 位,其实是将数字 80 对应的二进制 0101 0000 中的二进位向右移动 4 位,即:
80 >> 4
= 0101 0000 >> 4
= 0000 0101 # 正数补0,负数补1
= 5
2. 进制的相互转化
比如0.65换算成二进制就是:
0.65 × 2 = 1.3 取1,留下0.3继续乘二取整
0.3 × 2 = 0.6 取0, 留下0.6继续乘二取整
0.6 × 2 = 1.2 取1,留下0.2继续乘二取整
0.2 × 2 = 0.4 取0, 留下0.4继续乘二取整
0.4 × 2 = 0.8 取0, 留下0.8继续乘二取整
0.8 × 2 = 1.6 取1, 留下0.6继续乘二取整
0.6 × 2 = 1.2 取1,留下0.2继续乘二取整
3. 位运算常见用途
1. 使用异或交换进行变量交换
int a = 3, b = 5;
printf(“交换前:a=%d , b=%d\n”,a,b);
a = a^b;
b = a^b;
a = a^b;
printf(“交换后:a=%d , b=%d\n”,a, b);
2. 经典题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
- 关键思路:
1). 将所有的数异或一遍,剩下的数肯定是那两个只出现一次的数字的异或。
2).当你得到最终异或的数,通过找到异或数字的二进制种第一个1的位置,可以把整个数组分成两部分,每一部分都各自拥有一个只出现一次的数字,按照第一步的方法,分别把每组不同的哪个数字找出来即可。
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
//找出两个特殊数字异或的数
int target=0;
for(int i=0;i<array.length;i++){
target^=array[i];
}
int index=findFrist(target);
for(int i=0;i<array.length;i++){
//通过if分组,然后再异或从每组中获取那个特殊的值
if(((array[i]>>index)&1)==0)
num1[0]^=array[i];
else
num2[0]^=array[i];
}
}
//找出异或的数中的二进制第一个1.
int findFrist(int target){
int index=0;
while((target&1)==0&&index<32){
target>>=1;
index++;
}
return index;
}
- 题目:求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
- 思路:使用快速幂来计算
- 快速幂:
待解决。
- 题目:
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号
- 思路:首先看十进制是如何做的: 5+7=12,三步走
第一步:相加各位的值,不算进位,得到2。
第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。
第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。
同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。
第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。
第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。
public class Solution {
public int Add(int num1,int num2) {
/*
我们先来看一下十进制使怎么写的,首先,5+7,满十进一位,剩余的还在原位,
然后我们再算满多少个10,进多少位,
二进制也是一样,
1. 首先,我们先算不用进一位的数,使用异或操作(不同为1)因为只有0和1,所以为1证明这一位既不需要进,也不没有值
2. 接着,我们使用算需要金一位的数,使用&操作(都1才为1),然后将这些数左移一位,即是所有的进位数,
3. 接着再将左移后的数,再次与第一步的结果,比较,直到第二步,也就是不需要进位数了就结束循环
*/
while(num2!=0){
int temp=num1^num2;
num2=(num1&num2)<<1;
num1=temp;
}
return num1;
}
}
- 如何使用左移表示乘10;
res<<1+res<<3=22+28=2*10;