谈谈一个异或交换算法

以下全部用c举例

int a[10] = {0,1,2,3,4,5,6,7,8,9};

我们想交换数组a中第5个和第6个的值,通常想到的做法是创建一个中间变量作为中转,如下:

#include<stdio.h>void swap2num(int a[], int i, int j) {int tmp = a[i];a[i] = a[j];a[j] = tmp;
}int main() {int a[10] = {0,1,2,3,4,5,6,7,8,9};printf("before swap:a4=%d, a5=%d\n", a[4], a[5]);swap2num(a, 4, 5);printf("after swap:a4=%d, a5=%d", a[4], a[5]);return 0;
}

有种略显高明的做法,使用三次异或就可以实现同样的交换效果,如下:

#include<stdio.h>void swap2num(int a[], int i, int j) {a[i] = a[i] ^ a[j];a[j] = a[i] ^ a[j];a[i] = a[i] ^ a[j];
}int main() {int a[10] = {0,1,2,3,4,5,6,7,8,9};printf("before swap:a4=%d, a5=%d\n", a[4], a[5]);swap2num(a, 4, 5);printf("after swap:a4=%d, a5=%d", a[4], a[5]);return 0;
}

解读:

先谈谈异或的规则:
(1)相同为0,相异为1
(2) 异或满足交换律,即 a ^ b ^ c = a ^ ( b ^ c) = a ^ c ^ b
(3) N ^ N = 0, N ^ 0 = N;
那么,假设 a[i] = 甲, a[j] = 乙, 则第一次执行完 “a[i] = a[i] ^ a[j];”后:
a[i] = 甲 ^ 乙;
a[j] = 乙;
执行完 “a[j] = a[i] ^ a[j];” 后:
a[i] = 甲 ^ 乙;
a[j] =甲 ^ 乙 ^ 乙;
根据异或规则得到: a[j] = 甲 ^ (乙 ^ 乙) = 甲 ^ 0 = 甲; a[i] = 甲 ^ 乙;
再次执行完 “a[i] = a[i] ^ a[j];” 后:
a[i] = 甲 ^ 乙 ^ 甲 = 乙, a[j] = 甲;
至此,a[i]和a[j]完成交换;

深度解读:

异或操作又叫做 “无进位相加“,即相加的两个数的各个位相加但不产生进位;
然后我们从信息的角度再来审视一下代码,发现这其实是信息的叠加和分离,在这种思想下,我们可以用普通的加法也可以实现交换,当然是在不产生进位溢出的情况下,进位溢出意味着信息的丢失! (乘除也可以的,在乘积没有溢出的情况下)

#include<stdio.h>void swap2num(int a[], int i, int j) {//本函数的局限性--和不能产生进位溢出,所以这只是为了举例说明,现实中可不能这样写a[i] = a[i] + a[j];  // 以和的形式将两个数字叠加在一起,信息的叠加a[j] = a[i] - a[j];  //和减去其中一个必然得到另一个,信息的分离a[i] = a[i] - a[j];  //和减去其中一个必然得到另一个,信息的分离
}int main() {int a[10] = { 0,1,2,3,4,5,6,7,8,9 };printf("before swap:a4=%d, a5=%d\n", a[4], a[5]);swap2num(a, 4, 5);printf("after swap:a4=%d, a5=%d", a[4], a[5]);return 0;
}

同理,上面的异或交换也是信息的叠加和分离,但它的操作不产生进位,也就不会有溢出导致的信息丢失问题;
但是! 这个异或交换有个巨大的隐患!!即 i 和 j不能相等, 即不能让数组中相同位置的数进行交换,会发生什么问题呢?
记得上面的异或规则吗? N ^ N = 0,任意数和自己异或都等于0, 所以经历了异或交换以后,a[i] = 0, a[j] = 5, 完蛋了,没交换成功反而还让其中一个等于0了!
当然可以略作修改,做个判断,如下:

#include<stdio.h>void swap2num(int a[], int i, int j) {if (i == j)return;  //i等于j,即同一个位置交换时直接返回a[i] = a[i] ^ a[j];a[j] = a[i] ^ a[j];a[i] = a[i] ^ a[j];
}int main() {int a[10] = { 0,1,2,3,4,5,6,7,8,9 };printf("before swap:a4=%d, a5=%d\n", a[4], a[5]);swap2num(a, 4, 4);printf("after swap:a4=%d, a5=%d", a[4], a[5]);return 0;
}

plus:
linux源码中swap的实现方法,它就是用新建一个变量中转的方式实现的交换:

#define swap(a, b) \  
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)

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

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

相关文章

工程数学笔记 | 傅里叶级数/变换的本质理解

以下内容纯属个人学习记录&#xff0c;难免有误&#xff0c;欢迎指正~ 引子 虽已工作数宰&#xff0c;但当因为工作的需要再次碰到傅里叶级数/变换相关的知识时是还是难免汗流浃背&#xff0c;读书时的痛苦的回忆涌上心头&#xff0c;果然曾经欠下的总归是要偿还的&#xff0c…

Python基础语法之学习print()函数

Python基础语法之学习print函数 1、代码2、效果 1、代码 print("Hello World") print("Hello World1","Hello World2") print("Hello World1\n","Hello World2") print("Hello World",end" 默认结束符是行号…

传输层协议[精选]

网络: 跨主机通信. 互联网通信: 两点之间的通信路径有无数条. 集线器: 把一根网线差出来两根,但是同一时刻只能有一根线跑.交换机: 组建局域网.路由器: 本质就是将两个局域网连接起来 交换机和路由器之间的区别越来越模糊. 调制解调器: 使用电话线上网的时候,需要将电话线的模…

处理数据中的缺失值--填充缺失值

填充指的是利用现有知识/数据来确定缺失的数量值并填充的行为。我们有几个选择&#xff0c;最常见的是用此列其余部分的均值填充缺失值&#xff1b; 我们可以看到原始的数据集中有五行数据的plasma_glucose_concentration有缺失值&#xff1b; print(pima[plasma_glucose_con…

pandas 将DataFrame 转为txt文本,去除引号问题

法一(推荐)&#xff1a; import numpy as np np.savetxt(file.txt, df[列名]., fmt "%s")法二 此方法会导致原文中多 escapechar’ ’ 这种空格 import csv df[列名].to_csv(file.txt, sep , indexFalse, headerFalse, quotingcsv.QUOTE_NONE,escapechar )参考&am…

c++容器详解Vector、deque、list、set、multiset、map、multimap、queue、stcak、Array

容器 数据结构描述实现头文件向量(vector)连续存储的元素<vector>列表(list)由节点组成的双向链表,每个结点包含着一个元素<list>双向队列(deque)连续存储的指向不同元素的指针所组成的数组<deque>集合(set)由节点组成的红黑树,每个节点都包含着一个元素,…

C++:对象模型和this指针

对象模型&#xff1a; 成员变量和成员函数分开存储 在C中&#xff0c;类内的成员变量和成员函数分开存储 只有非静态成员变量才属于类的对象上 空对象占用空间&#xff1a; 1字节 C编译器会给每个空对象也分配一个字节空间&#xff0c;是为了区分空对象占内存的位置 每个…

根据密码构成规则检测密码字符串

从键盘输入密码字符串&#xff0c;程序根据给定密码构成规则检测并给出对应提示。 (笔记模板由python脚本于2023年11月27日 19:27:47创建&#xff0c;本篇笔记适合熟悉Python字符串str对象的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.…

Android12之logcat日志显示颜色和时间(一百六十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Android 12 打开网络ADB并禁用USB连接ADB

平台 RK3588 Android 12 Android 调试桥 (adb) Android 调试桥 (adb) 是一种功能多样的命令行工具&#xff0c;可让您与设备进行通信。adb 命令可用于执行各种设备操作&#xff0c;例如安装和调试应用。adb 提供对 Unix shell&#xff08;可用来在设备上运行各种命令&am…

ABAP: JSON 报文解析——/ui2/cl_json

1、JSON数组 报文格式如下&#xff0c;是JSON 数组类型的。 [{"I_TYPE":"V","I_BUSINESSSCOPE":"1001"},{"I_TYPE":"V","I_BUSINESSSCOPE":"1002"} ] json转换为SAP内表&#xff1a; TYP…

Redis入门保姆级教程

1. Redis入门 1.1 Redis简介 Redis是一个基于内存的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件。 官网:https://redis.io 中文网:https://www.redis.net.cn/ key-value结构存储&#xff1a; 主要特点&#xff1a; 基于内存存储&#xff0c;读写…

Gin框架如何使用并搭建一个后台管理系统(五)

如何判断用户登录是否登录????? 一、如何判断用户登录成功与否 1.请求接口 post : localhost:8888/admin/doLogin <form action="/admin/doLogin" method="post" id="myform"> <input type="hidden&qu…

五周年活动周历!AutoGen解析·技术畅聊·3大城市工坊本周启动!

飞桨星河社区在成立的5年以来&#xff0c;已汇集660万AI开发者&#xff0c;覆盖深度学习初学者、在职开发者、企业开发者、高校教师、创业者等&#xff0c;已成为AI领域最具影响力的社区之一&#xff0c;无论是AI爱好者还是AI开发者&#xff0c;都能在这里探索AI的无限可能。 飞…

docker 安装jekins

使用 Docker 安装 Jenkins 并实现项目自动化部署-阿里云开发者社区 http://mirror.esuni.jp/jenkins/updates/update-center.json Jenkins插件安装失败时这么做就搞定啦&#xff01; - 知乎 https://plugins.jenkins.io/maven-plugin/releases/ docker 安装jenkins下载不了…

uni-popup TypeError: Cannot read property ‘open‘ of undefined

我的代码是没问题的&#xff0c;因为之前popup没有问题&#xff0c;换了笔记本&#xff0c;重新安装了hbuilderx&#xff0c;现在uni-popup在页面的底端都显示出来了&#xff0c; 原因&#xff1a;uni-popup插件问题&#xff0c; 解决&#xff1a;我卸载hbuilder重新下了一遍&a…

计算机毕业设计|基于SpringBoot+MyBatis框架的仿天猫商城购物系统设计与实现

计算机毕业设计|基于SpringBootMyBatis框架的仿天猫商城购物系统设计与实现 迷你仿天猫商城是一个基于SSM框架的综合性B2C电商平台&#xff0c;需求设计主要参考天猫商城的购物流程&#xff1a;用户从注册开始&#xff0c;到完成登录&#xff0c;浏览商品&#xff0c;加入购物…

linux查看emmc分区信息(10种方法 )

目录 ## 1 emmc ## 2 uboot查看 ## 3 kernel查看 方法1 方法2 方法3 方法4 方法5 方法6 方法7 方法8 方法9 方法10 ## 1 emmc 我们要说的是&#xff0c;User Data Partition中的再分区 可简化为 ## 2 uboot查看 u-boot> mmc partPartition Map for MMC device…

C++值常用集合算法

C值常用集合算法 set_intersection #include<iostream> using namespace std; #include<vector> #include<numeric> #include<algorithm>class MyPrint { public:void operator()(int val){cout << val<<" ";} };void test() {v…

nodejs+vue+mysql皮具行李箱包包网上商城购物网站

本系统可分为两个大的模块&#xff0c;即前台用户模块和后台管理员模块&#xff0c;前台用户模块用户可以进行浏览查询皮具的各种信息&#xff0c;添加购物车&#xff0c;下订单等各种操作。后台管理员模块管理员可以进行皮具的处理&#xff0c;还有处理订单&#xff0c;皮具分…