【C语言刷题】——初识位操作符

【C语言刷题】——初识位操作符

    • 位操作符介绍
    • 题一、 不创建临时变量(第三个变量),实现两个数的交换
      • (1)法一
      • (2)法二
    • 题二、 求一个数存储在内存中的二进制中“一”的个数
      • (1)法一
      • (2)法二
      • (3)法三
    • 题三、 单身狗1
      • (1)法一
      • (2)法二
    • 题四、 单身狗二
      • (1)法一
      • (2)法二
      • (3)法三

位操作符介绍

位操作符有:

<<      //左移操作符
>>      //右移操作符
&       //按位与
|       //按位或
^       //按位异或
~       //按位取反

  注:他们的操作数必须是整数。

  更多关于位操作符介绍请看这篇文章:【C语言】——详解操作符(上)

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

(1)法一

  
参考代码:

#include<stdio.h>int main()
{int a = 0;int b = 10;a = a + b;b = a - b;a = a - b;printf("交换后a = %d b = %d\n", a, b);return 0;
}

  
代码讲解:

  相信这段代码大家都能看懂,这里我就不多解释了。
  
  但遗憾的是这个方法有一点问题:当 a 和 b 的值很大(但都不超过 i n t int int 的存储空间)时,他们相加会超过 int 的存储空间,导致丢失数据。
  
  那有什么更好的办法吗?有的,请看法二。

  

(2)法二

  
参考代码:

#include<stdio.h>int main()
{int a = 0;int b = 10;a = a ^ b;b = a ^ b;a = a ^ b;printf("交换后a = %d b = %d", a, b);return 0;
}

  
代码讲解:

首先,我们需掌握几个知识点:

  • 一个数与他自身异或为 0 0 0 ,即: a a a ^ a a a == 0 0 0
  • 任何数与 0 0 0 异或结果都为其本身,即: a a a ^ 0 0 0 == 0 0 0
  • 异或运算满足交换律,即: a a a ^ a a a ^ b b b == a a a ^ b b b ^ a a a

  第八行代码:b = a ^ b;,由于第七行代码:a = a ^ b; ,此时a = a ^ b;,即b = a ^ b ^ b,得b = a ^ 0 ;得 b = a

  同理,第九行代码:a = a ^ b;,由于第七行代码:a = a ^ b; 和第八行代码结果b = a,即:a = a ^ b ^ a,得 a = b

  我们可以这样来理解:我们把第七行代码a = a ^ b;当成是一把钥匙,碰到 a 得 b碰到 b 得 a

  

题二、 求一个数存储在内存中的二进制中“一”的个数

  

(1)法一

  
参考代码:

#include <stdio.h>int main()
{int num = 0;scanf("%d", &num);int count = 0;//计数while (num){if (num % 2 == 1)count++;num = num / 2;}printf("二进制中1的个数 = %d\n", count);return 0;
}

  
代码讲解:

  其实,该法的解题思路与在十进制中打印每一位是思路相同。在十进制中,要想获得每一位,我们的方法是:先余十,再除十,不断循环。这里,也是一样的只是因为是二进制改为先余二,再除而,不断循环,遇到结果为 1 ,则计数器加一。
  
  但是这个方法有点问题:它只能处理正数的情况,如果是负数,他就没办法了。为什么?因为:if(num % 2 == 1),负数余二永远不可能为 1,但num = num / 2;语句正常执行,输入复数的结果永远是 0。

  

(2)法二

  
参考代码:

#include<stdio.h>int main()
{int n = 0;scanf("%d", &n);int count = 0;for (int i = 0; i < 32; i++){if (n & 1){count++;}n = n >> 1;}printf("%d", count);return 0;
}

  
代码讲解:

  法二的思路是:给这个数的每一位都与上 1 (不断右移),因为与的逻辑是:有 0 为 0,全 1 为 1。当运算结果为 0 ,表示该位为 0, 结果为 1 ,该位为 1
  
图解(以5为例):
在这里插入图片描述
结果为1,计数器加一
  
5右移一位:
在这里插入图片描述
结果为0,计数器不变
  
5再右移
在这里插入图片描述
结果为1,计数器加一
  
接着不断右移,一共32次,因为后面的结果都是0,变不再一一赘述。
  
  但该方法一定要循环32次,有没有效率更高的方法呢?

  

(3)法三

  
参考代码:

#include<stdio.h>int main()
{int n = 0;scanf("%d", &n);int count = 0;while (n){n = n & (n - 1);count++;}printf("%d", count);return 0;
}

  
代码讲解:

该方法的核心:这个数本身与他自身减一与(&) 运算,不断循环
  

n = n & (n - 1);

或许大家一脸疑惑,别急,直接上图!

以15为例:
循环一次
在这里插入图片描述

循环两次:
在这里插入图片描述

循环三次:
在这里插入图片描述

循环四次:
在这里插入图片描述

  大家发现没有,每循环一次就会把最右边的 1 给消去,当最终把所有 1 消去变成零,循环结束,而我们只需要计算循环了多少次就能知道该数有几个 1 。

  

题三、 单身狗1

  
题目:

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

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

  

(1)法一

  
参考代码:

#include<stdio.h>int main()
{int arr[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4 };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < sz; i++){int flag = 0;int n = 0;for (int j = 0; j < sz; j++){if (i == j)continue;n = arr[i] ^ arr[j];if (n == 0){flag = 1;break;}}if (flag == 0)printf("单身狗是:%d\n", arr[i]);}return 0;
}

  
代码讲解:

  该方法想必大家都很容易想到,逻辑也很简单:遍历数组中的每一个数,每个数再遍历一遍除自身外的整个数组,遇到与自身一样的数就说明自己不是单身狗。
  这里就不再过多解释

  

(2)法二

  
参考代码:

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

  
解题思路:

这里再带大家重温一下按位异或的相关知识:
(1)一个数与他自身异或为 0 0 0 ,即: a a a ^ a a a == 0 0 0
(2)任何数与 0 0 0 异或结果都为其本身,即: a a a ^ 0 0 0 == 0 0 0

那么综合运用起来就是这题的解法啦

将数组元素全部异或
  
a = 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 1 ^ 2 ^ 3 ^ 4
a = 1 ^ 1 ^ 2 ^ 2 ^ 3 ^ 3 ^ 4 ^ 4 ^ 5
a = 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 0 ^ 5
a = 5

题四、 单身狗二

  
题目:

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

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

  
例如:

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

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

  

(1)法一

参考代码:

#include<stdio.h>int main()
{int arr[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4,6 };int sz = sizeof(arr) / sizeof(arr[0]);int count = 0;for (int i = 0; i < sz; i++){int flag = 0;int n = 0;for (int j = 0; j < sz; j++){if (i == j)continue;n = arr[i] ^ arr[j];if (n == 0){flag = 1;}}if (0 == flag){printf("单身狗是:%d\n", arr[i]);count++;}if (2 == count)break;}return 0;
}

  
代码讲解:

  这段代码的思路与上一题单身狗一的法一思路是相同的,
  
  即依次取出数组中的每个元素,让他与数组中剩下的元素比较,当遍历完整个数组依然没找到相同的数时,说明他是其中一个单身狗,计数器 +1 ,并打印;当计数器为二时,说明已找到全部单身狗,退出循环。

  

(2)法二

参考代码:

#include<stdio.h>int main()
{int arr[] = { 1,2,3,4,5,1,2,3,4,6 };int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < 32; i++){int j = 0;int last_0 = 0;int last_1 = 0;for (j = 0; j < sz; j++){if ((arr[j] & (1 << i)) == 0){last_0 ^= arr[j];}else if ((arr[j] & (1 << i)) != 1){last_1 ^= arr[j];}}if(last_0 != 0 && last_1 != 0){printf("%d %d", last_0, last_1);break;}}return 0;
}

  
代码讲解:

  做了上面的单身狗,我们想这题应该也可以用异或分方法来解,
  
  我们想到,如果将所有元素直接异或,肯定是无法直接找出两只单身狗,这时我们可以想到先将他们分组,让每一组都只有一只单身狗,再将两组全部异或就行了。那么怎么分组呢?
  
  我们看到因为数组两两元素相同,加上两只单身狗,所以数组总数一定是偶数,这时我们可以依次遍历数组中所有元素的二进制位数,将该位为 1 和为 0 的元素分成两组,分完组后,若两组的元素个数都为奇数(相同的数该位一定相同,一定被分到同一组,剩下一只单身狗,为奇数),则成功将两只单身狗分开,再分别异或两组中的所有元素就能找出两周单身狗啦,
  
  如果分完组两边都是偶数,则比较二进制下一位,直到分出奇数组。

  

(3)法三

参考代码:

#include<stdio.h>void findTwoNum(int arr[], int n, int * pnum1, int * pnum2)
{int i;int sum = 0;for (i = 0; i < 9; i++){sum ^= arr[i];} //先找到两个数互相异或的结果int pos;for (i = 0; i < 32; i++){if (sum & 1 << i){pos = i;break;}} //再找到有分歧的一位。在这一位上,两个数一定是一个1一个0*pnum1 = *pnum2 = 0;for (i = 0; i < 10; i++){if (arr[i] & 1 << pos){*pnum1 ^= arr[i]; //这一位是1的,放在数1里}else{*pnum2 ^= arr[i]; //这一位是0的,放在数2里}}
}

  
代码讲解:

  法二虽然用到了异或操作,但分起组来太过麻烦,效率并不高,有没有什么方法能实现快速分组呢?答案当然是有的。

  我们知道:两个相同的数异或为 0,将数组中的所有元素异或起来,得到的结果就是两只单身狗异或的结果。
  
  
  
  这时我们可能就要问了,那得到这个结果有什么用呢?肯定不止唯二这两个数异或才得出这个结果,其他两个数异或也有可能得到这个结果。

  确实如此,但我们别忘了异或的特点:相同为 0,相异为 1。我们只需要找到异或的结果的其中一个为“ 1 ”的位数,这说明在这个位,其中一只单身狗是0,另一只为1。

  这时,我们只需要将数组中的元素分两组:一组的元素在该位的值为 0,另一组该位值为 1,再将两组的所有元素分别异或起来,自然就得到两只单身狗啦。怎么样,是不是很巧妙呢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/746705.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

phpcms上传漏洞

原始漏洞 漏洞原理&#xff1a;我们上传一个zip的压缩包&#xff0c;它会解压然后删除其中不是.jpg .gig .png的文件 function check_dir($dir)&#xff1a;这是一个PHP函数的定义&#xff0c;它接受一个参数 $dir&#xff0c;代表要检查的目录路径。 $handle opendir($dir)…

【React】Vite创建React+TS项目

前提条件 有node环境&#xff0c;且node版本>18.0.0 创建项目 npm create vitelatest1.起项目名 2.选择框架 3.选择语言 TypeScript SWC 是指 Vite 使用 SWC&#xff08;Speedy Web Compiler&#xff09;作为 TypeScript 的编译器。 SWC 是一个针对 JavaScript 和 Ty…

客服销冠偷偷用的提效神器!无广很实用

近期发现我的同事每天上班必登录的一款软件——客服宝聊天助手&#xff0c;用过才发现&#xff1a;真客服办公的提效神器&#xff01;感兴趣的小伙伴请往下看~一、客服宝的简介&#xff1a;客服宝聊天助手&#xff0c;是一款跨平台快捷回复工具。自带多种功能&#xff0c;有效帮…

Python接口自动化测试post请求和get请求,获取请求返回值

引言 我们在做python接口自动化测试时&#xff0c;接口的请求方法有get,post等&#xff1b;get和post请求传参&#xff0c;和获取接口响应数据的方法&#xff1b; 请求接口为Post时&#xff0c;传参方法 我们在使用python中requests库做接口测试时&#xff0c;在做post接口测试…

C语言练习题【复试准备】

1、BoBo教KiKi字符常量或字符变量表示的字符在内存中以ASCII码形式存储。BoBo出了一个问题给KiKi&#xff0c;转换以下ASCII码为对应字符并输出他们。 //73,32,99,97,110,32,100,111,32,105,116,33 int main() {int arr[] {73,32,99,97,110,32,100,111,32,105,116,33};int i …

备战2024年汉字小达人活动:历年区级样题练习和解析(续)

今天我们继续来看汉字小达人活动的区级样题。区级样题是中文自修杂志社&#xff08;主办方&#xff09;发布的试题&#xff0c;主要是给学校老师选拔参考使用的&#xff0c;据了解&#xff0c;很多学校老师是直接用这个样卷在学校组织选拔&#xff0c;选拔成绩突出的同学报给主…

Pytorch学习 day10(L1Loss、MSELoss、交叉熵Loss、反向传播)

Loss loss的作用如下&#xff1a; 计算实际输出和真实值之间的差距为我们更新模型提供一定的依据&#xff08;反向传播&#xff09; L1Loss 绝对值损失函数&#xff1a;在每一个batch_size内&#xff0c;求每个输入x和标签y的差的绝对值&#xff0c;最后返回他们平均值 M…

Kafka配置SASL_PLAINTEXT权限。常用操作命令,创建用户,topic授权

查看已经创建的topic ./bin/kafka-topics.sh --bootstrap-server localhost:9092 --list 创建topic 创建分区和副本数为1的topic ./bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --topic acltest --partitions 1 --replication-factor 1 创建kafka用户 …

HTML静态网页成品作业(HTML+CSS+JS)——迪士尼公主介绍(6个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;使用Javacsript代码&#xff0c;共有6个页面。 二、作品演示 三、代码…

基于单片机的酒精浓度测试仪

摘 要 现如今&#xff0c;人们对生活的态度和生活方式变得不同,&#xff0c;不仅私家车成为了人们最普遍的交通工具&#xff0c;大多数人都有自己的私家车,而且人们对酒精的消耗量也越来越大&#xff0c;这些就导致酒后驾车行为越来越普遍&#xff0c;酒后驾车意外越来越频繁&…

【深度学习笔记】10_10 束搜索beam-search

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 10.10 束搜索 上一节介绍了如何训练输入和输出均为不定长序列的编码器—解码器。本节我们介绍如何使用编码器—解码器来预测不定长的序…

3dmax2020模型显示黑白不稳定---模大狮模型网

如果在3ds Max 2020中显示的模型出现黑白不稳定的情况&#xff0c;可能有几个常见原因和解决方法&#xff1a; 显卡驱动问题&#xff1a; 首先检查你的显卡驱动程序是否是最新版本。过时或不兼容的显卡驱动可能导致显示问题。建议更新到最新的显卡驱动程序&#xff0c;并确保其…

YOLOv9(3):YOLOv9损失(Loss)计算

1. 写在前面 YOLOv9的Loss计算与YOLOv8如出一辙&#xff0c;仅存在略微的差异。多说一句&#xff0c;数据的预处理和导入方式都是一样的。因此如果你已经对YOLOv8了解的比较透彻&#xff0c;那么对于YOLOv9你也只是需要多关注网络结构就可以。 YOLOv9本身也是Anchor-Free的&a…

编译esp32s3的ncnn,并运行mnist 手写数字识别

东哥科技&#xff0c;专注科技研发&#xff0c;wx交流&#xff1a;dg_i688 我的项目代码 https://github.com/cdmstrong/ncnn_on_esp32s3 下载ncnn git clone https://github.com/Tencent/ncnn.git安装idf 环境 这里直接按官网的可执行文件来就好了&#xff0c;直接安装完…

[mysql必备面试题]-mysql索引(B+ Tree )

一 B Tree 原理 1. 数据结构 B Tree 指的是 Balance Tree&#xff0c;也就是平衡树。平衡树是一颗查找树&#xff0c;并且所有叶子节点位于同一层。 B Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现&#xff0c;它具有 B Tree 的平衡性&#xff0c;并且通过顺序访问指针…

【python中处理日期和时间二】扩展内容datetime模块-pytz模块-dateutil模块

扩展内容&#xff1a;日期和时间 datetime模块&#xff1b;pytz模块&#xff1b;dateutil模块 一、 datetime模块 查看datetime模块函数&#xff1a; >>> import datetime >>> dir(datetime) [MAXYEAR, MINYEAR, UTC, __all__, __builtins__, __cached__…

2024最新国内外低代码平台大全

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

python面向对象的三大特性:封装,继承,多态

1、面向对象有哪些特性 三种&#xff1a;封装性、继承性、多态性 2、Python中的封装 在Python代码中&#xff0c;封装有两层含义&#xff1a; ① 把现实世界中的主体中的属性和方法书写到类的里面的操作即为封装 ② 封装可以为属性和方法添加为私有权限&#xff0c;不能直…

数据泄露态势(2024年2月)

监控说明&#xff1a;以下数据由零零信安0.zone安全开源情报系统提供&#xff0c;该系统监控范围包括约10万个明网、深网、暗网、匿名社交社群威胁源。在进行抽样事件分析时&#xff0c;涉及到我国的数据不会选取任何政府、安全与公共事务的事件进行分析。如遇到影响较大的伪造…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的安全帽检测系统(深度学习模型+UI界面代码+训练数据集)

摘要&#xff1a;开发先进的安全帽识别系统对提升工作场所的安全性至关重要。本文详细介绍了使用深度学习技术创建此类系统的方法&#xff0c;并分享了完整的实现代码。系统采用了强大的YOLOv8算法&#xff0c;并对其与YOLOv7、YOLOv6、YOLOv5的性能进行了详细比较&#xff0c;…