11.1 2 2 2 2=0

这是小学一年级课外读物上的一道题目。题目要求在数字与数字之间添上“+”或“-”号,使算式成立。

题目很简单,简单到了许多人可以不假思索地写出答案的地步。然而恰恰是这种简单却往往妨碍对求解过程的认真思考,以至于很少有人清楚答案究竟是如何得到的。这对于编程——描述计算的过程是非常不利的。不清醒地知道计算的步骤过程,就无法编程。如果问题再复杂一点,比如:

782 59 456 87 918=2010

这样的题目,恐怕就束手无策了。

很多人会想到穷举,把数字之间添上所有的运算可能。这的确是可切实可行的办法。问题在于,穷举不难,难的是写出真正简洁、有效、优雅的代码(不妨自己试一试)。这个穷举的难点在于,以往的穷举的对象都是数值对象,而这次要穷举的则是“运算动作”。

在C语言中,有两种东西是用来描述“动作”的。一是运算符,二是函数。加、减这两种运算即可以用运算符表达,这将得到一个值;也可以用函数描述,函数也可以有返回值。描述加减法的函数的函数原型都可以具有下面的形式。

11.1 2 2 2 2=0 - 图1

因此两个函数在形式上(参数类型和返回值类型)是可以统一的。根据前面的知识,函数名本身也是指针。由于这两个函数的函数名的类型相同,都是“int (*)(int,int)”类型,这就构成了把它们组织为数组的条件。而一旦把它们组织成了数组,穷举和运算的过程都不难表达。下面代码给出了求问题全部解的计算过程。

程序代码11-1

11.1 2 2 2 2=0 - 图2

11.1 2 2 2 2=0 - 图3

代码中用三重循环实现了对运算“动作”的穷举。由于加法、减法的优先级相同,所以可以从左到右运算,表达式“ysys1”进行的是前两个“2”的加法或减法运算,这个结果再与“2”进行加法或减法运算,这可以用表达式“ys[ys2] ( ysys1 , ER )”实现,以后依次类推。

由于加法、减法优先级相同,所以计算列举出的表达式显然还有其他的描述方法,比如“ysys2,ysys3 )”。请读者自己体会理解。

代码中可以改进的地方是,可以把“ys”数组定义为二维数组,这样就不必写那个显得有些啰唆的三重循环嵌套了。程序在结构上用二重循环嵌套就可以实现。但这种写法更为抽象,对初学者来说可能显得过于晦涩。有兴趣的读者可以自己试写一下。

从这个例子中,可以管窥到C语言数据类型的重要性和创造性。好的代码一定是以恰当的数据类型作为起点和基础的,因为数据类型是数据结构的基石。C语言所有的运算都是定义在具体的数据类型的基础之上的。构造出良好的数据类型,就可以实现更平易简单的算法,代码表达也更自然流畅。如果没有适当的数据类型,仅仅通过算法是很难弥补这个基础性的缺陷的。因此,读者可能已经注意到了,本书从头到尾都在强调数据类型这个最基本的概念。所谓“万丈高楼平地起”,离开了数据类型谈C程序或算法,是痴人说梦。

练习

在〇里添上“+”或“-”,使等式成立。通过编程实现。

6〇5〇4〇3〇2〇1=1