从“交换两个变量而不用临时变量”谈起

问题:写一个函数,实现交换两个变量,但不能用临时变量?

分析:交换两个变量的这一功能,我们用的比较多,也可以很容易的写出一个出来,但是题目要求的是不能用临时变量。并且题目也没有说明变量是什么类型,它是int,char,double,还是自定义的结构体,或者是类类型,虽然可以用模板从某种程度上解决这一些问题,但对于自定义的类型,还是不是很好处理。在这里先从最简单的说起,假设这里的变量是int型的。

一般如果我们要写一个交换整形变量的代码是

   1:  inline void Swap(int *a,int *b)
   2:  {
   3:       int temp;
   4:       temp=*a;
   5:       *a=*b;
   6:       *b=*a;
   7:  }

我们用到了临时变量temp。

思考一个问题我们为什么要用到临时变量呢?我们平常交换东西时,是否用到了临时的媒介呢?

比方说我手上有一个苹果,你手上有一个桔子,我想和你交换,是如何进行的,用到媒介没有呢?我们好像是直接交换的,这其中似乎没有用到什么媒介,但是仔细想想过程是用到了媒介的。交换可以归纳为两种方法,1:将物品直接从一个人的左手放到一个人的右手2:借助其它的容器,如果盘,先将物品放在果盘中,再去拿自己要的。其实这两个也只是一个方法而已,第一个借助的“容器”是我们的身上的另一只空闲的手,很容易忽略掉这个问题,以为我们没有用到其它媒介,要是想想我们只有一只手如何交换呢。

结论1:物质是有载体的,不管这物质是实体的,还是虚体。一个载体在同一时间上只能承载一种物质,于是在交换两个载体承载的物质时,是不可能同时进行的,估都要用到其它的媒介载体。回到计算机的问题上,存放变量也有载体的,它是内存,而变量可以说是一种虚体物质。这从直观上解释一般为什么我们写交换变量函数时要用到临时变量,也直接反映了编程不是离生活很远的,它不是另一个世界的思维。

即然如此,是不是没有办法了?方法只给那些勤于思考的人的。是一定要用到载体媒介吗?不用到就不行吗?

结合程序设计特点,可以有如下的代码

   1:  inline void Swap(int *a,int *b)
   2:  {
   3:      *a=*a+*b;
   4:      *b=*a-*b;
   5:      *a=*a-*b;
   6:  }

是不是很有意思,真的没有用到其它的临时变量啊!那我们上面的结论1是不是错了呢?当然不是,为什么可以直接就可以交换了呢?还是用上面的例子来说,两个人交换苹果和桔子但是每人只有一个手,也不借助其它的容器,那如何进行哟?有办法,就只是用一个手拿两样东西,也就是说先将苹果(桔子)给另一个人用一只手拿着,再从他手上拿桔子(苹果)。基本也就是代码的意思了。

结论2:看似不可能,但却可以的,要做的是仔细的去挖掘,多思考。

那上面的代码是不是就没有问题了?有。要考虑溢出的问题,程序中有一个加法,很可能使结果超出范围,也就是说一只手要是拿不了一个苹果和桔子怎样办?

要相信有问题是可以解决的,可以用assert等等方面处理一下,但不是最好,继续有如下的代码

   1:  inline void Swap(int *a, int *b)
   2:  {
   3:     *a ^= *b;
   4:     *b ^= *a;
   5:     *a ^= *b;
   6:  }
这是什么?一眼看不出是什么是吗?不慌,我们可以慢慢的一步步的分析。
对于位运算与、或、非,我们在处理数据的时候是经常要用到的。我们经常要用到的东西也是在基础的。
设uBitTest为测试数,值为2^n,也就是第n位为1。uDate为需要处理的数据。
1.将uDate的第n位置1
    uDate = uDate|uBitTest
2.将uDate的第n位置0
   uDate = uDate&~uBitTest
3.将uDate的第n位取反
    uDate = uDate ^uBitTest

掌握熟悉了这些在看上面的代码是不是要轻松多了,不是要溢出吗?不是一只手拿不下苹果和桔子吗?不要紧,我们可以一部分的交换啊,把苹果切开,桔子剥开来去交换,这样总可以拿下来吧。

结论3:载体承载物质是必需的,我们不能以改变,却可以改变载体承载的性质。载体的容量大小不能改变,但可以去改变承载物体的大小,照样可以达到想要的目的。真的是山穷水复疑无路,柳暗花明又一村。

到这里为止,对于简单的整形变量的交换的情况,已经基本上说清楚了,但并不是说可以去支持任何类型,在这里只是从最简单的例子开始,只是起个引子的作用,是给一些思路的问题。对于这个问题,还可以从内联汇编的方面去处理,可以看看汇编的代码是如何,从中得到一些启发;对于各种不同类型处理也有其各自的问题需要去处理,如对于类对象怎样去处理拷贝。对于好的库也可以去看看他们是怎样去写swap这个函数的。如stl,boost等,从中应该可以学到不少的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值