C语言中的逻辑运算符、位运算符及其应用技巧

是时候总结一波逻辑运算符和位运算符了。。。。。。
其实是更想总结一下位运算符的使用小技巧来体现其实用之处

  1. 逻辑运算符
&&	与:A && B,只要有一个条件为false,则结果为false
||	或:A || B,只要有一个条件为true,则结果为true
!	非:!A,若A为false,则结果为true。若A为true ,则结果为false
  1. 位运算符
&:	二进制按位与,有0即0
	例如:2 & 3 = 0010 & 0011 = 0010 = 2
|:	二进制按位或,有1即1
	例如:2 | 3 = 0010 | 0011 = 0011 = 3
~:	二进制按位取反(假设只有4位,实质int是32位的,但是原理是一致的)
	例如:2 = 0010,则~2 = 1101(注意这是补码,则原码是1011,符号位是1,表示负数)
	即-3
<<:二进制左移,相当于乘以2^n
	例如:1<<4 = 16
>>:二进制右移,相当于除以2^n
	例如:16>>4 = 1
^:	异或,二进制无进位相加
	例如:1^0 = 1	0^0 = 0		1^1 = 0 	0^1 = 1

用实例验证,正确

test.c
#include<iostream>
using namespace std;
int main()
{
	int a = 2&3;
	int b = 2|3;
	int c = ~2;
	int d = 1<<4;
	int e = 16>>4; 
	cout<<"2&3 	= "<< a <<endl;
	cout<<"2|3 	= "<< b <<endl;
	cout<<"~2  	= "<< c <<endl;	
	cout<<"1<<4 	= "<< d <<endl;
	cout<<"16>>4	= "<< e <<endl;
	cout<<"1^1	="<<(1^1)<<endl; 
	cout<<"0^1	="<<(0^1)<<endl; 
	return 0;
}
  

在这里插入图片描述
OK,概念总结完毕(更全面的可以看此链接:C语言所有的运算符
开始总结位运算符的实用技巧

  1. 异或^
    可以用于不利用中间变量来实现两个数的交换
    注意两点:
    (1)要交换的两个数据必须是整型,不适用于浮点型数据
    (2)要交换的两个数据必须是不同的内存地址,否则会出现错误
code:
void change(int &a, int &b)
{
	if(a == b)	return ;	//地址一样,直接退出 
	a = a^b;
	b = a^b;
	a = a^b;
}
  1. 按位&
    (1)已知集合{0,1,...,n-1}的元素共n个,我们知道子集的个数是2^n个(不要忽略空集Φ)。现在需要将所有的子集枚举出来,我们可以递归实现,也可以利用&运算符的方法来求取。
Code
#include<bits/stdc++.h>
using namespace std;
#define MAXN 105

void GetSubset_1(int n, int a[], int current)
{
	printf("{");
		for(int i = 0; i < current; ++i)
			printf("%d ",a[i]);
	printf("}");
	puts("");
	int pos = current ? a[current-1]+1 : 0;
	for (int i = pos; i < n; ++i)
	{
		a[current] = i;
		GetSubset_1(n,a,current+1);
	}
}

void GetSubset_2(int n)
{
	for(int i = 0; i < (1<<n); ++i)		//i代表第几个子集
	{
		printf("{ ");
		for(int j = 0; j < n; ++j)
		{
			if(i & (1<<j))		//判断事件j是否发生
			{
				printf("%d ",j);
			}		
		}
		printf("}\n");
	}
}

int main()
{
	int n = 3;
	int a[MAXN] = {};
//	GetSubset_1(n,a,0);	
	GetSubset_2(n);
	return 0;
}

(2)利用位与 & 运算,判断一个整数是否是2的整数次幂。由于二进制的权重是2,则一个数如果是2的整数次幂,则二进制表示的时候必然是最高位为1,其余都是0

keys:当一个数x是2的这个数次幂的时候,x&(x-1) = 0
因为减去1以后恰好降一位,后面的都会置为1,而前面全是0,按位&结果就是0
例子:x = 8 = (1000)2
	x-1 = 7 = (0111)2
	则1000 & 0111 = 0

Code:

bool fun(int num)
{
	return ( (num>0) && ((num & (num-1)) == 0) );
}

(3)利用&运算符求取给定数的二进制含有1的个数,利用了(2)的思路

/**
思想:将给定数的二进制从右到左消除1,直至为0,中间统计1的个数即可
*/
int Count_Of_Num_One(int num)
{
	int count = 0;
	while(num)
	{
		num = num&(num-1);
		count++;
	}
	return count;
}

猜你喜欢

转载自blog.csdn.net/bryant_xw/article/details/88579181