不使用临时变量的swap

一道经典的面试题如下:两个int型变量a和b,不使用临时变量,交换它们的值。
答案相信大家都耳熟能详了:

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

这段程序巧妙的安排运算顺序利用仅有的两个变量实现swap,它相当于这样一段程序:

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

可以发现它的技巧简单的说就是把本应放在临时变量c中的值放在了原有变量a中,a的值被覆盖。不过为什么a的值可以被覆盖掉呢?对这段程序一种比较technical的解释就是,它利用了 ^ (异或)运算的性质:

c = a ^ b  =>a = b ^ cb = a ^ c

但是,大家怎么想起来使用异或呢?使用异或有什么好处呢?两个变量既然要交换,那总归是要赋值的,而在C语言中有不能像Python那样直接一句搞定:

a , b = b , a

所以有这么一个结论:两个变量的最终赋值肯定是有先后顺序的。设a、b的初始值为A、B。假设b先完成赋值,即b已经存储了a的初始值A,现在要把b的初始值B放到a里面去。这时候可用的变量只有a了。也就是说在b完成赋值之后,a一定要包含b的初始值信息B,这样就或可能由a和b得到B,那么a一定包括A和B的信息。这里就是信息论的一点应用了。

可能的解

在C/C++语言中,怎么做运算才能保证把把两段信息放到一个变量中,知道一段信息后就可以分离出另一段信息呢?
最容易想到的运算可能是位运算。
C语言中的按位逻辑运算有这四种:
&:与,仅在两个operand均为1时为1
|:或,仅在两个operand均为0时为0
^:异或,当且仅当两个操作数相同时为0
~:非,取反操作
很容易看出,与运算的一个操作数为0时,结果永远是0,另一个操作数的信息就丢失了;或运算其中一个操作数为1时也会丢失另一个操作数的信息;而非运算是单目运算符;均不符合要求。再看看上文提到的异或的性质,则发现异或运算非常符合这个要求。2000年,异或的这个性质在通信领域带来了有影响力的理论:网络编码。有兴趣可以去wiki看一下。
学过数字电路的同学肯定记得,异或是可以使用与、或实现的:

a ^ b = ( a|b ) & ( ~( a&b ) )

这样,就可以使用与或得到同样的结果。不过,还要注意,如果a=b,那么这种解法就失效了。

除了异或和与或,还有其他运算符合这个要求吗?其他可用的运算符只有加减乘除了……
有的,还不少!请看:

a = a + b;
b = a;
a = a - b;

减乘除同样可以满足这个要求,这里不做赘述。不过,加减乘除都要注意溢出与精确度的问题。

上述六种方法,乘除受到的限制很多,用于float型或许还可以。而基于异或和与或的方法都是较合适的方法。
很显然,推广到任何指针,都能把指向的对象视为一个int/char数组,完成类似的swap。

不使用临时变量的swap再思考 -- 六种解法相关推荐

  1. 编译器会为const引用创建临时变量

    编译器会为const引用创建临时变量 引用不能绑定临时数据 将常引用绑定到临时数据时, const int &A; ==编译器会为临时数据创建一个新的.无名的临时变量,并将临时数据放入临时变量 ...

  2. C语言学习笔记07-1-语句结构:选择/循环(附三元运算符;DevC可以for定义临时变量的设置;continue、break、return;goto语句简单说明)

    选择/分支 与 循环/重复 语句结构 本质与流程图的三种结构类似,只是C语言没有until型循环,不难理解.文末捎带说一下goto语句. 结构化语句可以实现程序单一出口,goto 是非结构化的,会打乱 ...

  3. 学号20175313 《程序设计中临时变量的使用》第八周

    目录 程序设计中临时变量的使用 一.题目要求 二.运行结果截图 三.遇到的问题及其解决方法 四.代码链接 五.心得体会 程序设计中临时变量的使用 一.题目要求 //定义一个数组,比如int arr[] ...

  4. xx是一个类型 这在给定的上下文_基于上下文的派发:挂起临时变量内存

    最近做一些蒙卡相关的东西,然后遇到有一个可能很多人都会遇到的问题: 把所有的步骤都手写成原地(in-place)操作由于需要自己来保管各种中间变量会很麻烦(增加心智负担),但是用比较正常的方式去写又由 ...

  5. C++11 右值引用与常量左值引用保存临时变量(函数返回值)的底层分析

    右值引用保存临时变量(函数返回值)的问题 :临时变量是右值 1.普通变量接收函数返回值: 2.右值引用变量接收函数返回值: 3.用const int& 和右值引用是一样的效果,只是const ...

  6. 两个数字交换(不使用临时变量)

    #include<stdio.h> #include<stdlib.h>void swap(int* a, int* b)//普通交换 {int tmp = *a;*a = * ...

  7. 关于c++中的临时变量

    为什么写这样一篇文章? 本人是c++的初学者, 刚接触类这个概念没多久, 但是遇到了许多问题困扰我, 其中有一个问题尤为致命, 我问了许多前辈, 他们许多都没能如愿帮我彻底解决这个问题, 而写这篇文章 ...

  8. .NET异步和多线程系列(四)- 多线程异常处理、线程取消、多线程的临时变量问题、线程安全和锁lock

    本文是.NET异步和多线程系列第四章,主要介绍的是多线程异常处理.线程取消.多线程的临时变量问题.线程安全和锁lock等. 一.多线程异常处理 多线程里面抛出的异常,会终结当前线程,但是不会影响别的线 ...

  9. S7-200SMART PLC中使用临时变量TEMP无法实现自锁功能的解决办法

    S7-200SMART PLC中使用临时变量TEMP无法实现自锁功能的解决办法 很多小伙伴在初次使用临时变量时,将输出变量直接设置成OUT类型,但是在使用时却发现无法实现自锁等异常情况,下面就和大家分 ...

最新文章

  1. 华为鸿蒙运行视频,某游戏在华为鸿蒙运行,被识别成使用安卓模拟器
  2. 如何打赢一场唯快不破的比赛,看看他们的绝招
  3. ANDROID BITMAP内存限制OOM,OUT OF MEMORY
  4. VTK:相互作用之SelectAnActor
  5. 从一个帖子看部分大学生的学习心态
  6. C#模拟http 发送post或get请求
  7. synchronized同步块和volatile同步变量
  8. 从零开始刷Leetcode——动态规划(70.198.303)
  9. 翻译:protocol的高阶用法,在Swift 5中使用协议protocol构建自定义集合Collection
  10. 嵌入式和单片机有什么区别
  11. 计算机科学与因果关系,因果关系,概率和时间
  12. 从“H1N1病毒”看危机意识的重要性
  13. hdl_graph_slam的论文阅读
  14. 归并排序---------数构
  15. ZYNQ从放弃到入门(三)- 中断(一)
  16. 注册、登录、退出登录
  17. 没有发布服务器的 rpc 安全信息,或该信息无效,SQLServer之创建分布式事务
  18. OpenCV实践之路——雅虎色情图片检测神经网络试用报告
  19. 快来报名啦 | 图灵奖得主—— Joseph Sifakis明日重磅开讲
  20. 以外派的身份进大厂,或许条程序员升级的途径

热门文章

  1. Spark DataFrame小试牛刀
  2. session和cookie_JSP学习
  3. 详解spring框架入门到精通
  4. php 截图插件,react中有实现截图插件吗
  5. 有监督学习和无监督学习_比监督学习做的更好:半监督学习
  6. 改变css名称,样式命名规则?css
  7. HTML通过java信息保存,如何使用java邮件API将HTML格式的数据保存为java邮件的主体?...
  8. python中head_Python(Head First)学习笔记:六
  9. 一棵二叉树的中根线索二叉树_二叉树面试题刷题模板(终极版)
  10. 操作 mysql 不生成日志_利用Python操作MySQL数据库,以后不懂这些是要被鄙视的!...