您的位置:首页 > 其它

递归的实质以及递归时间复杂度的计算

2018-02-28 21:02 281 查看
说到递归,总会提到这么几个问题:

递归和迭代的区别是什么?

答:迭代式调别人,而递归是调自己

递归能不能改为迭代?

答:可以

那么递归的实质是什么?今天就说一下递归的实质

1.递归的实质:压系统栈

压到栈里的是当前的所有信息,包括当前跑到多少行,当前的参数和函数内的参数变量,等等

返回后再进行弹栈,然后读取弹栈后栈顶空间的信息,也就是返回到调用的地方。

我们也常常会说,递归可能会导致内存溢出也就是因为栈太过深了才可能会导致内存溢出。

递归可以改成迭代的原因就是,递归是系统在帮我们压栈,我们当然可以自己去申请栈空间进行操作,所以当然是可以改成迭代的。

2.递归空间复杂度

一般的空间复杂度可以使用master公式计算:

T(N) = aT(n/b) + O(N^d)
T(N):父问题的样本量
a:调用模块发生的次数
T(N/b):子问题的样本量
O(N^d):除去子问题调用过程外,剩下部分的时间复杂度
1) log(b,a) > d -> 复杂度为O(N^log(b,a))
2) log(b, a) = d -> 复杂度为O(N^d * logN)
2) log(b, a) < d -> 复杂度为O(N^d)


举个例子:

/*
* 递归二分求最大数
*/
public static int getMaxNum(int[] arr, int L, int R) {
// 递归结束条件:只剩下一个数
if(L == R)
return arr[L];

int mid = L +((R - L) >> 1);  //位运算取中值
int leftMax = getMaxNum(arr, L, mid);  //T(N/2)
int rightMax = getMaxNum(arr, mid + 1, R);  //T(N/2)

return Math.max(leftMax, rightMax);  //O(1)
}

// for test
public static void main(String[] args) {
int[] arr = {2, 3, 1, 6, 5};
System.out.println("max = " + getMaxNum(arr, 0, arr.length - 1));
}


从以上代码中分析

1.递归过程:

主函数调用getMax方法,第一次压栈是在
int leftMax = getMaxNum(arr, L, mid);
处,此时存入栈中的信息有:此时代码运行到的行数、该方法的参数:L = 0,mid = 2等,将此时的所有信息保存在申请的栈空间中,然后再进入调的getMaxNum方法中。。。一旦当前的L == R,即触发了
return arr[L];
此时进行弹栈操作,读取弹栈后的栈顶的信息,完全还原当时的信息,再继续执行。

2.递归时间复杂度的计算

T(N) = aT(n/b) + O(N^d)

T(N) = 2T(n/2) + O(N^0)

a = 2,b = 2,d = 0

可以使用master公式:

满足:log(b,a) > d -> 复杂度为O(N^log(b,a))

时间复杂度即为:O(N^1) = O(N)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: