今天看到了一个题目,又想起了以前的一个题目,这两个题目也算是有相关性吧。在这里总结一下。
题目1:不使用分支语句,循环语句,如:for while switch if goto 等关键字,输出1-n的整数。
题目2:求1+2+....n,要求不能使用乘除法、for、while、if、else、switch、case等关键字。
这两个题目的相关性就是不让使用循环和分支语句,这就是难点所在。对于题目1,我想到的就是静态成员变量,因为静态成员变量在内存中只有一份,所以可以共享,如果在这里用递归的话,最大的难点就是递归的出口怎么定义。目前,我没有想到可行的递归的方法。要使用静态成员变量,还有一个可行的方法那就是在类中来使用,我们可以通过不同的对象来实现内存中共享的静态成员变量的自增,从而输出1-n的自然数。如下是代码:
class D
{
public:
D()
{
cout << ++n << " ";
}
private:
static int n;
};
int D::n = 0;
void main()
{
D arr[100];
}
对于题目1,还有一个解法就是用宏定义。因为宏只是简单的代入,所以我们可以利用这点性质来实现嵌套输出1-n的自然数。例如:我们输出1-1000,代码如下:
#define A(x) x;x;x;x;x;x;x;x;x;x
void main()
{
int n = 0;
A(A(A(printf("%d ",++n))));
}
对于题目2,有了题目1的解,我们应该会有一个大概的思路。经上面的提示,我们应该会想到静态变量的应用,而且也是在类中,我们需要两个静态变量,一个用来保存自增的自然数,一个用来保存随时变化的和,这样我们就可以达到目的。代码如下:
class A
{
public:
A()
{
n++;
sum += n;
}
static int GetSum()
{
return sum;
}
private:
static int n;
static int sum;
};
int A::n = 0;
int A::sum = 0;
void main()
{
int n = 100;
A *p = new A[n];
int value = A::GetSum();
cout << value << endl;
}
题目2的另一种解法,真是让我觉得算法真的太精妙了。这也是看了July的文章后,才知道的这种解法。我根本就想不到这种方法。
重复一下这个思想吧。还是用递归,但是递归的难点就是出口怎么控制。在这里我们定义了两个函数,一个用来递归计算加和,另一个函数用来控制递归的函数出口。那就有两种情况,所以要二选一,那么我们可以用bool变量来控制。怎么根据给定的一个整数n来判断true和false呢?我们知道,如果n不是0,那么n就代表true,!n就表示false,那么!!n就表示true。当n是0时,正好相反。这就是关键所在,我们可以利用这点来控制递归函数出口。代码如下:
class B
{
public:
virtual int sum(int n)
{
return 0;
}
};
B *arr[2];
class C : public B
{
public:
virtual int sum(int n)
{
return arr[!!n]->sum(n-1) + n;
}
};
void main()
{
B b;
C c;
int n = 100;
arr[0] = &b;
arr[1] = &c;
int value = arr[1]->sum(n);
cout << value << endl;
}
上面用到了虚函数,这就是强大之处。多态竟然在这里用上了!我们用一个数组arr[2]保存两个变量,一个是类B的对象的指针,另一个是B类的子类的对象的指针。arr[1]->sum(n),就会调用C类中的sum函数,这里就实现了递归,当n递减到0时,由于!!0就是false,也就是0,那么arr[0]->sum()就会调用B类中的sum函数,此函数实现了递归的结束,也就是递归的出口。从而,我们利用多态实现了1-n的自然数的和。
题外话,这种思想,那是得多么精通c++的人才能想出来啊,自己太菜了!