位运算可以分为两大类:逻辑位运算符和位移位运算符;
逻辑位运算符:&(位与)、|(位或)、^(异或)、~(按位取反)
位移位运算符:<<(左移)、>>(右移)
关于每个位运算符的运算方法这里就不展开了,我们直接来学习一下几个有用的位运算算法题
1.2的幂
给定一个整数n,如果它是2的幂,返回true;否则返回false。
思路:首先如果n<0,那么n必然不是2的幂;其次,如果n是2的幂,那么它的二进制为100000(若干个0),则n-1为011111,因此n&(n-1)==0;
bool isPowerOfTwo(int n){
return (n > 0 ) && (n&(n-1))==0;
}
2.4的幂
给定一个整数n,如果它是4的幂,返回true;否则返回false。
思路:一个数如果是2的幂,那么它一定是4的幂,但是一个数如果是4的幂,它不一定是2的幂;
并且我们通过数学归纳法可知,2的偶数次幂mod3=1,2的奇数次幂mod3=2,而2的偶数幂就是4的幂;
bool isPowerOfFour(int n){
return (n>0) && (n& (n-1))==0 && n%3==1;
}
3.位1的个数
编写一个函数。输入是一个无符号整数,返回其二进制表达试中数字’1‘的个数。
思路:这题思路与第一题思路有关联,我们知道例如10000这个二进制,减去1后等于01111,两者位与后等于00000,这个过程即为10000的第一位‘1’被消去的过程,我们可以通过记录‘1’被消去的次数来得到‘1’的个数。
int hammingWeight(uint32_t n){
itn c=0;
while(n){
n&=(n-1);
++c;
}
return c;
}
4.交换数字
编写一个函数:不用临时变量,交换a与b的值。
思路:这里主要是学会使用异或运算符(两个相同的数异或得0,0与任何数异或都为这个数本身,并且满足交换律和结合律)
int* swapNumbers(itn* a,int aSIze, int* returnSize){
a[0] = a[0] ^ a[1];
a[1] = a[0] ^ a[1];
a[0] = a[0] ^ a[1];
*returnSize = 2; //这里是规定数组长度为2;
return a;
}
5.只出现一次的数字
给定一个非空整数数组,除了某个数字只出现一次外,其余数字均出现两次。找出那个只出现了一次的数字。
思路:这里主要是学会使用异或运算符(两个相同的数异或得0,0与任何数异或都为这个数本身,并且满足交换律和结合律),我们把数组中所有的数异或,相同的数异或必然为0,所有的0与最后那个单独的数异或结果为那个数本身。
int singleNumber(int* nums, int numsSize){
int i;
int sum = 0;
for(int i;i < numsSize ; i++){
sum=sum^nums[i];
}
}
6.汉明距离
两个整数之间的汉明距离指的是这两个数字对应的二进制位不同的位置数目。给定两个整数x和y,计算并返回它们之间的汉明距离。
思路:两个整数x和y异或之后,相同位置变为0,不同位置变为1,所以这题就变成了求两个整数异或之后位‘1’的个数;
int hanmingDistance(int x, int y){
int n = (x ^ y );
int c = 0;
while(n){
n&= (n-1);
++c;
}
}
7.交替位二进制数
给定一个正整数n,检查他的二进制表示是否总是0,1交替出现。(换句话数就是,二进制表示中相邻两位的数字永不相同)
思路:我们从低到高依次将两位二进制数与3位与。一个整数的二进制表示中,如果相邻为00.那么位与11等于11,如果相邻为11,那么位与11等于00,11的十进制为3,00的十进制为0;
int hasAlternatingBits(int n){
while(n){
if((n&3)==3||(n&3)==0){
return false;
}
n>>=1;
}
return true;
}