移位操作符与位操作符详解

简介: 移位操作符与位操作符详解

移位操作符

<<左移            >>后移

移位操作符的操作数只能是整数  ,移动的是的是操作数的二进制数码位置,整数在内存中存放的是补码

这里移动的的是整数的补码,打印时是原码对的值。

左移操作符:技巧:左边抛弃,右边补零

int main()
{
  int a = 3;
  int c = a << 1;
  printf("%d", a);//3
  printf("%d", c);//6
  int d = -3;
  int e = d << 1;
  printf("%d", e);//-6
  return 0;
}

如图:

25742fa8c37046679f313d4ad6deeded.png

右移操作符

右移分两种,1.逻辑移位   左边用零补充,右边丢弃。2.算术移位。左边用该值的符号位填充,右边丢弃

移位采用算术右移还是逻辑右移取决于编译器.

在vs采用的是算术右移

int main()
{
  int a = -5;
  int b = a >> 1;
  printf("%d", b);//-3
  return 0;
}

e7893087f77843c7a7a3c9676d872552.png

需要值得注意的是,一个数的二进制位最多时三十二位,移位操作注意其移位大小。

位操作符

位操作符共有三个:& (按位与)              |(按位或)                 ^(按位异或)

对于他们的操作数,也是整数。

int main()
{
  int a = 3;
  int b = -5;
  int c = a & b;//按位与 对应二进制位同真为真,有一个为假就是假      1为真,0为假
  printf("%d", c);//3
  int d = a | b;//按位或  对应的二进制位同假为假,有一个真为真
  printf("%d", d);//-5
  int e = a ^ b;//按位异或,对应的二进制位相同为假,不同为真
  printf("%d", e);//-8   
}

如图:

fca7ef897a44427ea1d5af525a0e9d53.png

注意的一点是:

0^a = a
3^3^5 = 5
3^5^3 = 5
异或是支持交换律的

例题

交换两个数,不用第三方变量。

int main()
{
  int a = 3;
  int b = 5;
  printf("交换前:a=%d b=%d\n", a, b);
  a = a ^ b;
  b = a ^ b;
  a = a ^ b;
  printf("交换后:a=%d b=%d\n", a, b);
  return 0;
}

当然这里除了运用按位异或。还可以用

int main()
{
    a = a + b;
  b = a - b;
  a = a - b;
  printf("交换后:a=%d b=%d\n", a, b);
}

单身狗问题

给一组数,在这里里面,有两个数字只出现一次,其他数数字都是成对出现的,找出只出现一次的两个数字

1 2 3 4 5 1 2 3  4 6

解题思路:所有的数字异或在一起,因为相同的二进制位异或之后是零,零和一个数异或是他本身。

而这里我们要找两个只出现一次的数,所以这里需要对数进行分组,使得每一组只有一个”单生狗“数,之后再进行异或操作。那麽如何分组呢?

在这里单生狗数是 5和6 ,我们可以发现5与6异或之后的结果是0 1 1,他的二进制位最后一位是1,那我们就按每个数二进制位最后一位是否是1来分组。

1 0 1 - 5

1 1 0 - 6

0 1 1

所以在此之前所有的数异或之后,我们去寻找最后该结果的二进制位哪一位是1,标记该位置。遍历二进制是从后往前的。之后再将每一个数右移至该位置,按位与1判断是否为0,为1则说明该位置的二进制位是0分一组,将该组数异或在一起,为零说明二进制位是1分为一组,将该组数异或在一起,即可以求得该单身狗数。

首先我们要对数进行分组,假设有数组的元素是:1,2,3,4,5,1,2,3,4,6

我们按它的二进制位最后一位是否为1进行分组:

第一组:

最低位是1的数字:1 1 3 3 5

第二组:

最低位是0的数字:2 2 4 4 6

在这里,我们也可以以它的倒数第二位是否为1进行分组

第一组:

倒数第二位是1的数字:6 2 2 3 3

第二组:

倒数第二位是0的数字:1 1 4 4 5

void find_single_dog(int arr[], int sz, int* sd1, int*sd2)
{
  //1. 把所有的数字异或在一起
  int ret = 0;
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    ret ^= arr[i];
  }
  //2. 计算ret的二进制中哪一位是1
  int pos = 0;
  for (i = 0; i < 32; i++)//总共32位二进制位
  {
    if (((ret >> i) & 1) == 1)
    {
      pos = i;
      break;
    }
  }
  //3. 分组异或
  for (i = 0; i < sz; i++)
  {
    if (((arr[i] >> pos) & 1) == 1)
    {
      *sd1 ^= arr[i];
    }
    else
    {
      *sd2 ^= arr[i];
    }
  }
}
int main()
{
  int arr[] = { 1,2,3,4,5,1,2,3,4,6};
  int sz = sizeof(arr) / sizeof(arr[0]);
  int x = 0;
  int y = 0;
  find_single_dog(arr, sz, &x, &y);
  printf("%d %d\n", x, y);
  return 0;
}
int main()
{
  char arr[10] = { 0 };
  sprintf(arr, "%d", 1234);
  printf("%s\n", arr);//1234
  return 0;
}


相关文章
|
存储 C语言
C语言操作符[算数操作符,赋值操作符,单目操作符,移位操作符]
C语言操作符[算数操作符,赋值操作符,单目操作符,移位操作符]
|
存储 编译器 C语言
【C语言初阶】带你轻松玩转所有常用操作符(1) ——算数操作符,移位操作符,位操作符
【C语言初阶】带你轻松玩转所有常用操作符(1) ——算数操作符,移位操作符,位操作符
94 0
|
7月前
|
存储
位运算符和位操作符
位运算符和位操作符
32 0
^(按位异或)操作符详解
^(按位异或)操作符详解
C#中算数运算符及逻辑运算
C#中算数运算符及逻辑运算
86 0
异或运算符简单逻辑运算 a^=b
异或运算符简单逻辑运算 a^=b
131 0
深入理解算数运算符
深入理解算数运算符
55 0
|
存储 编译器 C语言
C语言——操作符(上)算术、移位、位、赋值操作符
C语言——操作符(上)算术、移位、位、赋值操作符