【基础算法】位运算

概念

在这里插入图片描述
异或(x⊕y或x ^ y)

高低位交换:https://www.luogu.com.cn/problem/P1100
题意:给定一个32 3232位整数x xx,在二进制下交换其前16 1616位与后16 1616位,输出最终的数。
答案为ans = (x >> 16) | (x << 16)
注意此处使用32 3232位无符号整数进行计算,这样x << 16会自然溢出,导致前16 1616位被丢弃,恰好满足要求。
参考:

#include <cstdio>
using namespace std;

int main()
{
	unsigned int x;
	scanf("%u", &x);
	printf("%u\n", (x >> 16) | (x << 16));
	return 0;
}

位运算模板

求n的第k位数字: n >> k & 1
返回n的最后一位1lowbit(n) = n & -n

1.求n的第k位数字 : n>>k&1 (n右移k位, 然后&1)

 int n = 15; //00000000000000000000000000001111
 for(int i=31;i>=0;i--){
   	System.out.print( n>>i & 1 ); //00000000000000000000000000001111
 }

2.返回n的最后一位1 : lowbit(n) = n & -n 这里的 -n 也就是 ~n+1(取反加一)

public static int  lowbit(int n){
        return n & -n;
}

lowbit(x)即为二进制下x xx的最低位,如lowbit(10010) = 10、lowbit(1) = 1。严格来说0没有lowbit,部分情况下可视为lowbit(0) = 1。利用lowbit函数可实现树状数组等数据结构。

模板题

AcWing 801. 二进制中1的个数
输入样例
5
1 2 3 4 5
输出样例
1 1 2 1 2

思路 : 使用 lowbit(n) 依次算出每个末尾1的数 然后减去后继续 lowbit

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n' 
const int N=1e5+10;
int a[N];
int b[N];
 
int lowbit(int x)
{
	return x&(-x);
}
 
signed main()
{   
	  ios::sync_with_stdio(0);
	  cin.tie(0);cout.tie(0); 
	  int n;
	  cin>>n;
	 while(n--)
	 {
		  int x;
		  cin>>x;
		  int cnt=0;
		  while(x)
		  {
			  	x-=lowbit(x);//减去最后一个1以及后面的数(二进制) 
			  	cnt++;
		  }
		  cout<<cnt<<" ";
	  }
}

位运算的应用

1.x & 1

一个数补码表示中的第k位数字

int func(int n, int k)
{
	return ((n >> k) & 1);
}

求补码中含有1的个数

int func(int n)
{
	int countn = 0;
	while (n)
	{
		if (n & 1) countn++;
		n = n >> 1;
	}
	return countn;
}

偶数位与奇数位分开输出

void func(int n)
{
	std::cout << "奇数位输出:>";
	for (int i = 31; i >= 1; i -= 2)
	{
		std::cout << ((n >> i) & 1) << ' ';
	}
	std::cout << std::endl << "偶数位输出:>";
	for (int i = 30; i >= 0; i -= 2)
	{
		std::cout << ((n >> i) & 1) << ' ';
	}
}

2.x & (-x)

返回x的最后一位1及之后的数字
lowbit(x):返回x的最后一位1及之后的数字
x=101000 lowbit(x)=1000
x=1010 lowbit(x)=10

判断一个数是否是2的n次方

bool func(int n)
{
	return (n == (n & (-n)));
}

求补码中含有1的个数

int func(int n)
{
	int countn = 0;
	while (n)
	{
		countn++;
		n -= (n & (-n));
	}
	return countn;
}

3.x & (x - 1)

求补码中含有1的个数(微软)

int func(int x)
{
	int countx = 0;
	while (x)
	{
		countx++;
		x = x & (x - 1);
	}
	return x;
}

判断一个数是否是2的n次方

bool func(int x)
{
	x = x & (x - 1);
	return x ? false : true;
}

两个数补码位上不同数的数量

int func(int x, int y)
{
	int ret = x ^ y, count = 0;
	while (ret)
	{
		count++;
		ret = ret & (ret - 1);
	}
	return count;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值