位运算一些理解

位运算全面总结,关于位运算看这篇就够了-CSDN博客

一些运算规则可以看这篇文章,基础运算为:

&两个位都为1时,结果才为1
|两个位都为0时,结果才为0
^异或两个位相同为0,相异为1
~取反0变1,1变0
<<左移各二进位全部左移若干位,高位丢弃,低位补0
>>右移各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

一些总结:1.异或判断数组中的数值是否重复,重复的数值可通过异或删除。

2.位运算交换两整数

 a ^= b;
      b ^= a;
      a ^= b;

3.位运算改变正负性和求绝对值

~ a + 1;

对于正数而言,补码就是原码,所以按位取反再 + 1 +1 +1则得到对应真值负数的补码,而对于负数,其补码进行按位取反再 + 1 +1 +1则得到对应真值正数的补码,变为原码

力扣中有一些题目使用bitset 来运算二进制(把二进制当成一个数组来操纵,另外结合一些二进制的性质)std::bitset 是 C++ 标准库中的一个类,用于表示二进制位序列。它提供了一种方便的方式来处理二进制数据,尤其适用于位运算操作。用法有:

常用函数

  • size() 返回 std::bitset 的长度
  • count() 返回 std::bitset 中值为 1 的位的数量
  • any() 返回 std::bitset 中是否存在值为 1 的位
  • none() 返回 std::bitset 中是否所有位都是 0
  • all() 返回 std::bitset 中是否所有位都是 1
  • test(pos) 返回 std::bitset 中位于 pos 位置的值
  • set(pos)std::bitset 中位于 pos 位置的值设为 1
  • reset(pos)std::bitset 中位于 pos 位置的值设为 0
  • flip(pos)std::bitset 中位于 pos 位置的值取反
  • to_ulong() 返回 std::bitset 转换成的无符号整数值
  • to_ullong() 返回 std::bitset 转换成的无符号长整数值
  • bitset<8>foo(string("10011011"));
    
    cout<<foo.count()<<endl;//5  (count函数用来求bitset中1的位数,foo中共有5个1
    cout<<foo.size()<<endl;//8  (size函数用来求bitset的大小,一共有8位
    
    cout<<foo.test(0)<< endl;//true  (test函数用来查下标处的元素是0还是1,并返回false或true,此处foo[0]为1,返回true
    cout<<foo.test(2)<<endl;//false  (同理,foo[2]为0,返回false
    
    cout<<foo.any()<<endl;//true  (any函数检查bitset中是否有1
    cout<<foo.none()<<endl;//false  (none函数检查bitset中是否没有1
    cout<<foo.all()<<endl;//false  (all函数检查bitset中是全部为1
    

一:赋值,字符串赋值

bitset<4>a1;//长度为4,默认以0填充
bitset<8>a2;//长度为8,将12以二进制保存,前面用0补充


string s = "100101";
bitset<10>a3(s);//长度为10,前面用0补充

//实验检测,char在普通环境不能直接赋值给bitset
//要开c++11,针不戳
char s2[] = "10101";
bitset<13>a4(s2);//长度为13,前面用0补充
//所以这玩意noip上不能用……

cout<<a1<<endl;//0000
cout<<a2<<endl;//00001100
cout<<a3<<endl;//0000100101
cout<<a4<<endl;//0000000010101

二可以直接进行位运算,就是一个二进制

 std::bitset<4> bitset1("1010");
 std::bitset<4> bitset2("0110");
 ​
 std::bitset<4> bitset3 = bitset1 & bitset2; // 按位与运算
 std::bitset<4> bitset4 = bitset1 | bitset2; // 按位或运算
 std::bitset<4> bitset5 = bitset1 ^ bitset2; // 按位异或运算
 std::bitset<4> bitset6 = ~bitset


std::bitset<4> bitset1("0101");
 ​
 std::bitset<4> bitset2 = bitset1 << 2; // 左移 2 位,结果为 "010100"
 std::bitset<4> bitset3 = bitset1 >> 1; // 右移 1 位,结果为 "0010"

显示时可直接转为字符串进行显示

 std::bitset<4> bitset1("1010");
 std::string str = bitset1.to_string(); // "1010"

。。

例子:下一个数。给定一个正整数,找出与其二进制表达式中1的个数相同且大小最接近的那两个数(一个略大,一个略小)。

(1)找略大的那一个数:
找第一个左边一位为0的1向左交换(01xxx这种形式,01xxx->10xxx),并将位于其右边高位的1全部尽可能后移;
边界应该不能超过2147483647,大于这个则返回-1。

(2)找略小的那一个数:
找第一个右边一位为0的1向右交换(10xxx这种形式,10xxx->01xxx),并将位于其右边低位的1全部尽可能前移;
若数的最高有效位及其右边的数位全为1则不存在更小数,返回-1

vector<int> findClosedNumbers(int num) {
        //return {1,1};
        vector<int> nums(31,0);
        for(int i=0;i<=30;++i){
            nums[i]=pow(2,i);
        }//预处理一个数组,{1,2,4,8,16...}某一位为1,nums[i]^INT_MAX可以将num[i]取反,即0000 ... 0001转化为1111 ... 1110
        vector<int> res(2,-1);
        int flag1=1,flag0=1;
        for(int i=0;i<30;++i){
            if((nums[i]&num)==0&&flag1&&nums[i+1]&num) {
                //遇到了第一个10
                res[1]=num-nums[i+1]+nums[i];
                flag1=0;
                int k=-1,l=i;//k记录从最右边开始未处理的1,l处理10转化为01后的0
                while(l&&(nums[l-1]&num)==0&&nums[k+1]&num){//处理类似1001,10011这种情况(转化完应为0110,01110)
                    res[1]=res[1]-nums[++k]+nums[--l];
                    if(l==0) break;
                }
            }
            if((nums[i]&num)&&flag0&&(nums[i+1]&num)==0){
                //遇到了第一个01
                res[0]=num-nums[i]+nums[i+1];
                flag0=0;
                int k=-1,l=i;//k记录从最右边开始未处理的0,l处理01转化为10后的1
                while(l&&nums[l-1]&num&&(nums[k+1]&num)==0){//处理类似1111000,1111100这种情况(转化完应为10000111,10001111)
                    res[0]=res[0]+nums[++k]-nums[--l];
                    if(l==0) break;
                }
            }
        }
        return res;

给定两个整型数字 NM,以及表示比特位置的 iji <= j,且从 0 位开始计算)。

编写一种方法,使 M 对应的二进制数字插入 N 对应的二进制数字的第 i ~ j 位区域,不足之处用 0 补齐

//int转bit,bit做运算,先补位后移动
    int insertBits(int N, int M, int i, int j) {
         for (int k = i; k <= j; ++ k)
        {   //举例说明: (1 << 3) 表示 00001000,取反后得 11110111
            // N &= (11110111) 表示将 N 的第3位置零了
            N &= ~(1 << k);//要插入的部分置0
        }
        return N + (M << i);

int 类型的数temp中有几个1

 int count = 0;
        while (temp != 0) {
            temp &= (temp - 1);  // 去掉二进制表示的最右边的1
            count++;
        }
        return count;

int t=0b01010101010101010101010101010101;以二进制的方式定义整数

后面的数是二进制数。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值