二年级开始玩编程,如今已经五年级了。从具象到抽象,最近用 C 语言多些。
要交换两个变量的内容,用个临时变量帮忙很容易:
int a, b;
a = 3;
b = 5;
int tmp = a;
a = b;
b = tmp;
Lucas 却很享受不使用第三个临时变量的小花招。比如:
int a, b;
a = 3;
b = 5;
printf("%d %dn", a, b); // 3 5
a = a + b;
b = a - b;
a = a - b;
printf("%d %dn", a, b); // 5 3
所以,只要碰到需要交换两个变量的时候,他总是掏出这个小花招。我心里忍俊不住,真不嫌脑累。他后来告诉我:“这个小花招从未失手过。”
这一天终于来了。
在实现洗牌算法的时候,需要交换数组中的两个元素的位置,相当于交换两张牌的位置。Lucas 一如既往地再次拿出小“妙”招。
结果出状况了,52 张牌用 1~52代表,洗过之后有时(很容易重现)出现了 0 ,甚至还不止一个。
如果将小妙招换成平淡无奇的办法,即图中注释掉的用一个临时变量帮忙的普通招数,问题就消失了。经过一番研究,咱们知道 0 的出现,是由于某张牌自己跟自己换位置。但牌“3”和自己“换”位置,还应该是牌“3”啊,怎么就变成“0”了呢?
Lucas 很郁闷,自己心爱多年的小妙招难道靠不住了?即使是两个数一样,小妙招也照样灵验啊。比如:
int a, b;
a = 3;
b = 3;
printf("%d %dn", a, b); // 3 3
a = a + b;
b = a - b;
a = a - b;
printf("%d %dn", a, b); // 3 3
当我让他试试把所有的 b 换成 a 时,他就彻底明白了。:D
int a;
a = 3;
printf("%d %dn", a, a); // 3 3
a = a + a;
a = a - a;
a = a - a;
这是导致小妙招“失灵”的原因。
解决方案特简单,如果洗牌过程中,一张牌需要跟自己换位置时,啥也别干就得了呗。有趣的是,Lucas 第一次写
if(c == d) continue;
时,把第一个 n 上下翻了个个,写成 coutinue 了。
后来,我把这个可遇不可求的精彩案例,分享给 Lucas 的双胞胎弟弟 Marius 时,也就是在同样这个环节,Marius 也“完整无误”写出了同样的 coutinue 。
我服了,双胞胎。