数据结构与算法一 - 位运算

本文通过实例解析位运算符如按位与(&), 或(|), 异或(^), 取反(~), 左移(<<), 右移(>>)在计算机中的工作原理,并演示如何利用它们进行数值交换、加减运算及奇偶数判断,揭示了编程中的高效技巧。
摘要由CSDN通过智能技术生成

📝 个人简介

⭐ 个人主页:我是段段🙋‍
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:数据结构与算法
🛸 支持段段:点赞👍、收藏⭐、留言💬

前言

什么是位运算?

数据都是以二进制的形式存储在设备中,即0、1两种状态,计算机对二进制数据进行的运算(+、-、*、/)都叫位运算,即将符号位共同参与的运算

首先引入log方法

const { log } = console

举一个简单的例子看下cpu是如何进行计算的

let a = 35
let b = 47
let c = a + b

计算两个数的和,而在计算机中都是以二进制进行计算的,所以上面定义的变量在计算机内部先转换为二进制再进行相加

350 0 1 0 0 0 1 1
470 0 1 0 1 1 1 1
-------------------
    0 1 0 1 0 0 1 0

位运算概述

位运算主要包括按位与(&)按位或(|)异或(^)取反(~)左移(<<)右移(>>),具体如下

符号描述运算规则
&两个位都为1时,结果才为1
|两个位都为0时,结果才为0
^异或两个位相同为0,相异为1
~取反0变为1,1变为0
<<左移各二进位全部左移若干位,高位丢弃,低位补0
>>右移各二进位全部右移若干位,对无符号数,高位补0;有符号数,有的补符号位(算术右移),有的补0(逻辑右移)

按位与运算符(&)

定义:参加运算的两个数据,按二进制位进行"与"运算

运算规则:0 & 0 = 0、0 & 1 = 0、1 & 0 = 0、1 & 1 = 1,两个数据相应位同时为1时,结果才为1,否则结果为0

例如 3 & 5

30000 0011
50000 0101
------------
   0000 0001

// 即3 & 5的运算结果为1
log( 3 & 5 ) // 1

按位或运算符(|)

定义:参加运算的两个数据,按二进制位进行"或"运算

运算规则:0 | 0 = 0、0 | 1 = 1、1 | 0 = 0、1 | 1 = 1,两个数据相应位只要有一个为1,其值为1

例如 3 | 5

30000 0011
50000 0101
-------------
   0000 0111

// 即3 | 5的运算结果为7
log( 3 | 5 ) // 7

异或运算符(^)

定义:参加运算的两个数据,按二进制位进行"异或"运算

运算规则:0 ^ 0 = 0、0 ^ 1 = 1、1 ^ 0 = 1、1 ^ 1 = 0,两个数据相应位相同为0,相异为1

例如 3 ^ 5

30000 0011
50000 0101
------------
   0000 0110

// 即3 ^ 5的运算结果为6
log( 3 ^ 5) // 6

异或的几条性质

1. 交换律 a ^ b = b ^ a
2. 结合律 (a ^ b) ^ c = a ^ (b ^ c)
3. 对于任何数x,都有 x ^ 0 = x,x ^ x = 0
4. 自反性 a ^ b ^ b = a ^ 0 = a

log( (3 ^ 5) === (5 ^ 3) ) // true
log( ((3 ^ 5) ^ 7) === (3 ^ (5 ^ 7)) ) // true
log( 3 ^ 0, 3 ^ 3) // 3 0
log( 3 ^ 5 ^ 5 ) // 3

实例一:交换两个数值

  • 借助第三个变量
let num1 = 1
let num2 = 2
function exchange(val1, val2){
    let temp = val1
    val1 = val2
    val2 = temp
    return[val1, val2]
}
[ num1, num2 ] = exchange(num1, num2)
log( num1, num2 ) // 2 1
  • 加减法
let num1 = 1
let num2 = 2
function exchange(val1, val2){
    val1 += val2 // val1 = 1 + 2 = 3
    val2 = val1 - val2 // val2 = 3 - 2 = 1
    val1 -= val2 // val1 = 3 - 1 = 2
    return [val1, val2]
}
[ num1, num2 ] = exchange(num1, num2)
log( num1, num2) // 2 1
  • 位运算
let num1 = 1
let num2 = 2
function exchange(val1, val2){
    val1 ^= val2 // val1 = val1 ^ val2 = 1 ^ 2
    val2 ^= val1 // val2 = val2 ^ val1 = 2 ^ (1 ^ 2) = 1 ^ (2 ^ 2) = 1 ^ 0 = 1
    val1 ^= val2 // val1 = val1 ^ val2 = (1 ^ 2) ^ 1 = (1 ^ 1) ^ 2 = 2
    return [val1, val2]
}
[ num1, num2 ] = exchange(num1, num2)
log(num1, num2) // 2 1

取反运算符(~)

定义:参加运算的一个数据,按二进制进行"取反"运算

运算规则:~1 = 0、~0 = 1,对一个二进制数按位取反,即0变1,1变0

// 对所有整数取反 = 本身的相反数 - 1
log( ~1, ~0) // -2 -1

左移运算符(<<)

定义:将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)

若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2

let a = -4
log( a << 2) // -16

右移运算符(>>)

定义:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃

a = a >> 2 将a的二进制位右移2位,左补0 或者 左补1得看被移数是正还是负

// 操作数每右移一位,相当于该数除以2
let a = 4
log( a >> 2 ) // 1

实例二:判断奇偶数

之前我们判断得时候会这样写

function isParity(val){
    return val % 2 == 0 ? true : false
}

log( isParity(5) ) // false
log( isParity(4) ) // true

用位运算来实现

function isParity(val){
    return val & 1 == 1 ? false : true
}

log( isParity(5) ) // flase
log( isParity(4) ) // true

实例三:位运算经典问题

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号

function sum(num1, num2){
    let a = num1 ^ num2
    let b = num1 & num2
    b <<= 1
    if(b == 0){
        return a
    }
    return sum(a, b)
}

log( sum(5, 3) ) // 8

具体实现过程如下, 以5 + 3为例进行过程分析

第一步:num1 = 0101(5),num2 = 0011(3), a = num1 ^ num2 = 0110,b = num1 & num2 = 0001,b << = 1 = 0010 
第二步:num1 = 0110,num2 = 0010, a = num1 ^ num2 = 0100,b = num1 & num2 = 0010,b << = 1 = 0100
第三步:num1 = 0100,num2 = 0100, a = num1 ^ num2 = 0000,b = num1 & num2 = 0100,b << = 1 = 1000
第四步:num1 = 0000,num2 = 1000, a = num1 ^ num2 = 1000,b = num1 & num2 = 0000,b << = 1 = 0000

此时a就是计算的结果

~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是段段

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值