什么是递归?
若一个对象部分的包含自己或用它自己给自己定义,那么我们说这个对象是递归的;若一个过程直接或间接的调用自己,那么这个过程是递归的。
递归的思想是把问题分解为规模更小具有与原问题相同解法的子问题,因此可以让我们思考的方式更加简单,程序也更加简练。不过就递归函数而言递归增加了压栈开销,因此空间复杂度比较高。
递归条件:
(1)、减小问题规模,并使子问题与原问题有相同解法。
(2)、设置出口,如果没有出口那么程序会一直递归下去。
递归的简单运用
斐波那契数列是递归问题中非常典型的一个了,我们常用循环的方式解斐波那契数列,循环解法:
long Fibonacci2(size_t N) //时间复杂度O(n),空间复杂度O(1)
{
long first = 1;
long second = 1;
long sum = 0;
if (N < 3)
return 1;
else
{
for (size_t i = 3; i <= N; i++)
{
sum = first + second;
first = second;
second = sum;
}
return sum;
}
}
这种解法是比较高效的一种解法。
现在来看递归解法:
long Fibonacci1(size_t N) //时间复杂度O(2^N),空间复杂度O(n)
{
if (N < 3)
return 1;
else
return Fibonacci1(N - 1) + Fibonacci1(N - 2);
}
这种解法思维方式非常简单,但是时间复杂度特别高,一般不建议采用这种方法。
我们来看一种比较高效的递归解法:
long Fibonacci3(long first, long second, size_t N) //时间复杂度O(n),空间复杂度O(1)
{
if (N < 3)
return second;
else
return Fibonacci3(second, first + second, N - 1);
}
如果说前一种递归解法是由后向前计算,那么这种解法就是由前向后计算了,这种递归方式属于尾递归,因此在进行递归时函数只会使用第一次压栈所开辟的栈空间,在一个栈空间内循环,而不会开辟别的栈空间,所以这种方式时间复杂度为O(N),空间复杂度为O(1),是一种非常高效的递归方式。
除此之外还有一种递归解法:
long *Fibonacci4(size_t N) //时间复杂度O(n),空间复杂度O(n)
{
long *array = new long[N + 1];
if (N == 0)
return NULL;
array[0] = 0;
array[1] = 1;
for (size_t i = 2; i <= N; i++)
{
array[i] = array[i - 1] + array[i - 2];
}
return array;
}
这种递归解法并不比上一种方式高效,之所以写出来是因为这种递归方式是在一个代码块内递归,而不是上面那种函数的递归。
斐波那契数列解法非常多,在此仅给出4种解法。希望各位大神斧正。