移位和位操作符的应用

前言

       这里我将分享几道编程题目,主要使用移位和位操作符进行解答。
       我们首先要知道两个数字进行异或操作的时候结果是位0的,即 a ^ a = 0,并且我们还要知道 0 和任何数字异或的结果都是这个数字的本身,即 0 ^ a = a;

交换变量(一道变态的面试题)

不能创建临时变量(第三个变量),实现两个数的交换

解析

       既然不能创建变量,那么我们可以尝试从位操作符入手,首先 a ^ b 的结果放入 a 中,再异或 b 就会得到原先 a 的值,把异或的结果放入 b 中, a 异或这个 b 的话,就会得到这个 b 的值。

代码实现

#include 

int main()
{
	int a = 5, b = 10;
	a = a ^ b;   // 注意斜杠后面的 a 和 b 是原先的值
	b = a ^ b;  // a ^ b ^ b = a ^ 0 = a
	a = a ^ b;  // a ^ b ^ a = b ^ 0 = b
	printf("%d\n%d\n", a, b);
	return 0;
}

求一个整数储存在内存中二进制中 1 的个数

方法一

       我们可以使用一个 1 进行左移操作,遍历三十二位 (y因为整型是四个字节就是32个比特位),用计数器count 来记录有多少个 1 ,这样就可以了

#include 

int main()
{
	int n;
	scanf("%d", &n);
	int count = 0;
	for (int i = 0; i < 32; i++)
	{
		if (n & (1 << i))
		{
			count++;
		}
	}
	printf("%d\n", n);
	return 0;
}

方法二

       我们可以使用一个公式就是 n & (n - 1) , 这个公式能帮我们去掉每一位上的 1 ,这样的话,我们就可以用循环来遍历待测的数字的二进制上的每一位。


#include 

int main()
{
	unsigned int n;
	scanf("%d", &n);
	int count = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	printf("%d\n", n);
	return 0;
}

你们猜猜看为什么我要使用unsigned ,因为害怕整型溢出,很简单如果 n 的二进制位是32个1,是个负数,你减去一就会整型溢出,所以为了避免这一种情况出现,我们使用unsigned 来接受 n 的数值。

二进制某位上置位 0 或 1

将数字13的二进制序列的第五位设置为1,之后再改为0.

解析

       这道题很简单,对 1 进行移位操作,将结果与13 进行a按位或( | )操作即可。再改为 0 也是一样的,就是将 1 移位操作再按位取反加 ( & )操作即可。

代码实现

#include 

int main()
{
	int n = 13;
	n = n | (1 << 4);
	printf("%d\n", n);
	n = n & (~(1 << 4));
	printf("%d\n", n);
	return 0;
}

单身狗1

在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。

例如:

数组中有:1 2 3 4 5 1 2 3 4,只有5出现一次,其他数字都出现2次,找出5

解析

       我们设置一个 tmp 为0,然后用循环来遍历每一个数字与tmp进行异或,最后打印tmp的值就是那个“单身狗”!

代码实现

#include 

int main()
{
	int arr[9] = { 1,2,3,4,5,1,2,3,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0, tmp = 0;
	for (i = 0; i < sz; i++)
	{
		tmp ^= arr[i];
	}
	printf("%d\n", tmp);
	return 0;
}

单身狗2

一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。

编写一个函数找出这两个只出现一次的数字。

例如:

有数组的元素是:1,2,3,4,5,1,2,3,4,6

只有5和6只出现1次,要找出5和6.

解析

       在有了单身狗1 的基础上,我们知道所有数字异或之后就会找到那个落单的数字,但是这道题是有两个落单的数字,那么我们将所有数字进行异或后,得到的结果就是这两个落单的数字异或的结果。既然如此,这个结果能不能进行二次加工来分离这两个数字呢?在二进制的基础上,异或是相同的为0,不同的为1,两个不同的数字必然在某些二进制位是不同的,那么我们就可以将这个结果第几位为 1 作为分界线,来区分这两个数字,我们可以将它们分开来,然后对这两组进行分别异或,就会得到这两个数字。

代码实现

#include 

void Find_Single_Dog(int* p, int n, int *num1, int *num2)
{
	int tmp = 0;
	int i = 0;
	for (i = 0; i < n; i++)
	{
		tmp ^= p[i];
	}
	int k = 0;
	for (i = 0; i < 32; i++)    //找到第几位为1
	{
		if (tmp & (1 << i))
		{
			break;
		}
	}
	k = i;
	for (i = 0; i < n; i++)
	{
		if (p[i] & (i << k))
		{
			*num1 ^= p[i];
		}
		else
		{
			*num2 ^= p[i];
		}
	}
}

int main()
{
	int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int num1, num2;
	num1 = num2 = 0;
	Find_Single_Dog(arr, sz, &num1, &num2);
	printf("%d\n%d\n", num1, num2);
	return 0;
}

你可能感兴趣的:(初始c语言,c语言)