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
	但是如果取反得到得结果符号位是0,即正数,值就是这个数
	例如:-4 = 1100【原】= 1011【反】= 1100【补】
	~(-4) = 0011 = 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
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 <>4	= "<< e <C语言中的逻辑运算符、位运算符及其应用技巧_第1张图片
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
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<

(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;
}

你可能感兴趣的:(C/C++)