面试题 46(*),求1+2+..+n (巧妙使用函数指针和面向对象思想,amazing)

很苛刻的条件。我自己一开始想从等差数列公式n*(n+1)/2 入手,/2可以用 >>1表示,但是n*(n+1)怎么求真是伤透了脑筋。

虽然可以用递归,但是递归也是有返回判断的,这里判断语句都被禁止了。

 

看了答案才知道原来还可以这样玩。。。

要学会灵活的运用面向对象和函数指针啊亲。

解法一:利用 new 一个n元素的数组代替了循环的功能。

如果不用公式,仅仅累加来做,那么最难的地方自然就是如何绕过循环了。

解法一非常巧妙地利用了构造函数和static成员来解决这个问题。

class Temp的static成员Sum用来保存累加结果,N用来自增,这样不论有多少instance,他们都共享一个static成员,从而通过定义n个Temp的实例,来实现累加。

class Temp
{
public:
    Temp() { ++ N; Sum += N; }

    static void Reset() { N = 0; Sum = 0; }
    static unsigned int GetSum() { return Sum; }

private:
    static unsigned int N;
    static unsigned int Sum;
};

unsigned int Temp::N = 0;
unsigned int Temp::Sum = 0;

unsigned int Sum_Solution1(unsigned int n)
{
    Temp::Reset();

    Temp *a = new Temp[n];
    delete []a;
    a = NULL;

    return Temp::GetSum();
}

缺点在于,比较费空间。

 

解法二:递归思想,递归终止函数和继续递归函数分开定义,通过函数指针,两个函数就可以放到一个数组中。!!n 可以在n大于0时返回1,等于0时返回0,从而完成了n到数组下标的选择开关。

这种解法的核心就是:递归终止函数和继续递归分开定义,然后通过一种方法,实现根据n的值选择哪一个函数。

这里的方法是通过函数指针来讲两个函数放入数组,再用!!n完成选择。

typedef unsigned int (*fun)(unsigned int);

unsigned int Solution3_Teminator(unsigned int n) 
{
    return 0;
}

unsigned int Sum_Solution3(unsigned int n)
{
    static fun f[2] = {Solution3_Teminator, Sum_Solution3}; 
    return n + f[!!n](n - 1);
}

这里也巧用static让代码更简洁。

其实这样写更加容易理解些:

#include <stdio.h>
typedef unsigned int (*fun)(unsigned int);
fun f[2];

unsigned int Solution3_Teminator(unsigned int n) 
{
    return 0;
}

unsigned int Sum_Solution3(unsigned int n)
{
    return n + f[!!n](n - 1);
}

int main(){
    f[0] = Solution3_Teminator;
    f[1] = Sum_Solution3;
    
    printf("%d\n",Sum_Solution3(6));
}

 

解法三:核心和解法二一样,也是将递归继续函数和递归终止函数分开定义。也是用过n!!来完成数组下标的选择。区别在于,解法二使用了函数指针,从而可以将两个函数放到一个数组中,解法三使用了多态的性质来完成这一步。

多态中,父类型的变量被实例化为子类的实例,会调用子类的函数。这正好可以用来完成“将不同函数存放到一个数组中”的要求。

定义父类A,子类B,然后将递归终止函数和递归继续函数分别作为这两个类的同名成员函数,父类设置为virtual,就完成了多态的设置。

这样就可以定义存放类型A的数组,第一个元素是A实例,第二个元素是B实例。

 A;
A* Array[2];

class A
{
public:
    virtual unsigned int Sum (unsigned int n) 
    { 
        return 0; 
    }
};

class B: public A
{
public:
    virtual unsigned int Sum (unsigned int n) 
    { 
        return Array[!!n]->Sum(n-1) + n; 
    }
};

int Sum_Solution2(int n)
{
    A a;
    B b;
    Array[0] = &a;
    Array[1] = &b;

    int value = Array[1]->Sum(n);

    return value;
}

 

解法二和解法三相对来说要节省空间,

posted on 2014-03-10 01:56  Felix Fang  阅读(397)  评论(0编辑  收藏  举报

导航