1.3 顺序结构程序设计

例题1-2 三位数反转

输入一个三位数,分离出它的百位、十位和个位,反转后输出。

样例输入:

127

样例输出:

721

【分析】

首先将三位数读入变量n,然后进行分离。百位等于n/100(注意这里取的是商的整数部分),十位等于n/10%10(这里的%是取余数操作),个位等于n%10。程序如下:

程序1-6 三位数反转(1)


#include<stdio.h>
int main()
{
  int n;
  scanf("%d", &n);
  printf("%d%d%d\n", n%10, n/10%10, n/100);
  return 0;
}

此题有一个没有说清楚的细节,即:如果个位是0,反转后应该输出吗?例如,输入是520,输出是025还是25?如果在算法竞赛中遇到这样的问题,可向监考人员询问(4)。但是在这里,两种情况的处理方法都应学会。

提示1-10:算法竞赛的题目应当是严密的,各种情况下的输出均应有严格规定。如果在比赛中发现题目有漏洞,应向相关人员询问,尽量不要自己随意假定。

上面的程序输出025,但要改成输出25似乎会比较麻烦——必须判断n%10是不是0,但目前还没有学到“根据不同情况执行不同指令”(分支结构程序设计是1.4节的主题)。

一个解决方法是在输出前把结果存储在变量m中。这样,直接用%d格式输出m,将输出25。要输出025也很容易,把输出格式变为%03d即可。

程序1-7 三位数反转(2)


#include<stdio.h>
int main()
{
  int n, m;
  scanf("%d", &n);
  m = (n%10)*100 + (n/10%10)*10 + (n/100);
  printf("%03d\n", m);
  return 0;
}

例题1-3 交换变量

输入两个整数ab,交换二者的值,然后输出。

样例输入:

824 16

样例输出:

16 824

【分析】

按照题目所说,先把输入存入变量ab,然后交换。如何交换两个变量呢?最经典的方法是三变量法:

程序1-8 变量交换(1)


#include<stdio.h>
int main()
{
  int a, b, t;
  scanf("%d%d", &a, &b);
  t = a;
  a = b;
  b = t;
  printf("%d %d\n", a, b);
  return 0;
}

可以将这种方法形象地比喻成将一瓶酱油和一瓶醋借助一个空瓶子进行交换:先把酱油倒入空瓶,然后将醋倒进原来的酱油瓶中,最后把酱油从辅助的瓶子中倒入原来的醋瓶子里。这样的比喻虽然形象,但是初学者应当注意它和真正的变量交换的区别。

借助一个空瓶子的目的是:避免把醋直接倒入酱油瓶子——直接倒进去,二者混合以后,将很难分开。在C语言中,如果直接进行赋值a=b,则原来a的值(酱油)将会被新值(醋)覆盖,而不是混合在一起。

当酱油被倒入空瓶以后,原来的酱油瓶就变空了,这样才能装醋。但在C语言中,进行赋值t=a后,a的值不变,只是把值复制给了变量t而已,自身并不会变化。尽管a的值马上就会被改写,但是从原理上看,t=a的过程和"倒酱油"的过程有着本质区别。

提示1-11:赋值a=b之后,变量a原来的值被覆盖,而b的值不变。

另一个方法没有借助任何变量,但是较难理解:

程序1-9 变量交换(2)


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

这次就不太方便用倒酱油做比喻了:硬着头皮把醋倒在酱油瓶子里,然后分离出酱油倒回醋瓶子?比较理性的方法是手工模拟这段程序,看看每条语句执行后的情况。

在顺序结构程序中,程序一条一条依次执行。为了避免值和变量名混淆,假定用户输入的是a0b0,因此scanf语句执行完后a=a0b=b0

执行完a=a+b后:a=a0+b0b=b0

执行完b=a-b后:a=a0+b0b=a0

执行完a=a-b后:a=b0b=a0

这样,就不难理解两个变量是如何交换的了。

提示1-12:可以通过手工模拟的方法理解程序的执行方式,重点在于记录每条语句执行之后各个变量的值。

这个方法看起来很好(少用一个变量),但实际上很少使用,因为它的适用范围很窄:只有定义了加减法的数据类型才能采用此方法(5)。事实上,笔者并不推荐读者采用这样的技巧实现变量交换:三变量法已经足够好,这个例子只是帮助读者提高程序阅读能力。

提示1-13:交换两个变量的三变量法适用范围广,推荐使用。

那么是不是说,三变量法是解决本题的最佳途径呢?答案是否定的。多数算法竞赛采用黑盒测试,即只考查程序解决问题的能力,而不关心采用了什么方法。对于本题而言,最合适的程序如下:

程序1-10 变量交换(3)


#include<stdio.h>
int main()
{
  int a, b;
  scanf("%d%d", &a, &b);
  printf("%d %d\n", b, a);
  return 0;
}

换句话说,我们的目标是解决问题,而不是为了写程序而写程序,同时应保持简单(Keep It Simple and Stupid,KISS),而不是自己创造条件去展示编程技巧。

提示1-14:算法竞赛是在比谁能更好地解决问题,而不是在比谁写的程序看上去更高级。