基础算法学习:位运算

基础算法学习:位运算

精简总结:

&:按位与,1&0=0,0&1=0,0&0=0,1&1=1,只有都为1时才为1.

|:按位或,1|1=1,1|0=1,0|1=1,0|0=0,只有都为0时才为0.

^:按位异或,1^1=0,1^0=1,0^a=a,相同为0,不同为非0的那个数.

>>:右移,a>>x,表示a除以2^x;

<<:左移,a<<x,表示a乘2^x;

~:把0变成1,把1变成0;

-x=~x+1;

(1)lowbit(x)

将十进制数的二进制表示的最低位1取出来。

int lowbit(int x)
{
    return x&-x;
}

如x的二进制表示时100,-x在计算机中为~x+1,则~x=011,~x+1=111,那么就有

(100)&(111)=(100),这样就可以把最低位上面的1取出来。

(2)把n对应二进制表示中第k位取出来(注意有第0位)

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

(3)输出所有小于k的十进制

for(int i=0;i<1<<k;i++)
    cout<<i;

详细介绍:

位运算基础与常见操作

位运算是对数字的二进制位进行的操作,常用于需要高效处理数据、节省时间和空间的场景。通过位运算,我们可以实现许多常见的算法优化,尤其是在与数学和计算机内部存储结构相关的算法中。下面我们将介绍几种常见的位运算及其应用。

1. 常见的位运算符

位运算符主要有以下几种,每种操作的含义都与二进制位的操作相关。

  • 按位与(&)
    a & b​ 操作会对 a​ 和 b​ 的每一位进行“与”运算,只有两个操作数的相同位都为1时,结果才为1,否则为0。
    例子:

    5 = 0101
    3 = 0011
    ------------
    5 & 3 = 0001  // 结果为 1
    
  • 按位或(|)
    a | b​ 操作会对 a​ 和 b​ 的每一位进行“或”运算,只有两个操作数的相同位都为0时,结果才为0,否则为1。
    例子:

    5 = 0101
    3 = 0011
    ------------
    5 | 3 = 0111  // 结果为 7
    
  • 按位异或(^)
    a ^ b​ 操作会对 a​ 和 b​ 的每一位进行“异或”运算,两个操作数相同的位为0,不同的位为1。
    例子:

    5 = 0101
    3 = 0011
    ------------
    5 ^ 3 = 0110  // 结果为 6
    
  • 右移(>>)
    a >> x​ 操作会将 a​ 的二进制表示向右移动 x​ 位,相当于对 a​ 进行除以 2^x​。
    例子:

    8 = 1000
    8 >> 2 = 0010  // 结果为 2
    
  • 左移(<<)
    a << x​ 操作会将 a​ 的二进制表示向左移动 x​ 位,相当于对 a​ 进行乘以 2^x​。
    例子:

    2 = 0010
    2 << 2 = 1000  // 结果为 8
    
  • 按位取反(~)
    ~a​ 操作会对 a​ 的二进制表示进行按位取反,把 0​ 变成 1​,把 1​ 变成 0​。
    例子:

    5 = 0101
    ~5 = 1010  // 结果为 -6(补码表示)
    
  • 负数的表示(-x)
    在计算机中,负数是以补码形式表示的,-x = ~x + 1​。
    例子:

    x = 5
    ~x = 1010
    -x = ~5 + 1 = 1010 + 1 = 1011  // 结果为 -5
    

2. 常见的位运算技巧

(1) lowbit(x)

lowbit(x)​ 作用是将 x​ 的二进制表示中最低位的 1 取出来。这在一些算法中,尤其是与树状数组(Fenwick Tree)相关的算法中非常有用。

代码实现:

int lowbit(int x) {
    return x & -x;
}

原理:

  • -x​ 是 x​ 取反加 1,即补码表示。
  • x & -x​ 结果就是保留最低位的 1,其他位为 0。

例子:

x = 12 = 1100 (二进制)
-x = 4 = 0100
x & -x = 1100 & 0100 = 0100  // 结果为 4
(2) 取出二进制表示中的第 k 位

如果你想获取一个整数 n​ 在二进制表示中第 k​ 位的值(0 或 1),可以通过右移 k​ 位然后与 1 进行按位与来实现。

代码实现:

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

例子:

n = 12 = 1100 (二进制)
k = 2
get(12, 2) = (12 >> 2) & 1 = 3 & 1 = 1  // 第 2 位为 1
(3) 输出小于 k 的所有十进制数

若需要输出所有小于 k​ 的十进制数,可以利用位移运算(1 << k​)来表示范围,遍历所有可能的二进制数。

代码实现:

for (int i = 0; i < (1 << k); i++) {
    cout << i << endl;
}

例子:

k = 3
输出:
0
1
2
3
4
5
6
7

3. 位运算的实际应用

位运算在许多实际问题中都有应用,特别是在优化性能方面。例如:

  • 计算某个数的二进制中 1 的个数:可以利用 x & (x - 1)​ 的技巧快速消除最低位的 1。
  • 判断一个数是否为 2 的幂x > 0 && (x & (x - 1)) == 0​。
  • 数值范围控制:使用位运算进行数字范围的控制和处理。

4. 总结

位运算是计算机底层的基础操作,它在很多算法中起到至关重要的作用,特别是在需要高效处理数据的场景中。掌握位运算能让你在处理某些问题时更加得心应手,提高程序的效率。

  • 位运算操作符常用且直接,理解其原理后可以应用于实际问题中。
  • 位运算常常用于优化时间复杂度或空间复杂度,是面试中常见的考点之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值