递归四条基本法则:
《数据结构与算法分析-java语言描述》 P7
- <mark>基准情形</mark>。必须总要有某些基准情形,它无需递归就能解出。
- <mark>不断推进</mark>。对于那些需要递归求解的情形,每次递归调用都必须要使状况朝向一种基准情形推进。
- 设计法则。假设所有的递归调用都能运行。
- <mark>合成效益法则(compound interest rule)。在求解一个问题的同一实例时,切勿在不同的递归调用中取做重复性的工作</mark>。
用递归
减少运行时间
- 通过递归,缩小问题的范围。O(logN)
分析使用栈空间的量
像二叉查找树,的平均深度(栈空间的使用量)O(logN),就没问题
(有待理解)
不用递归
- 递归调用之后,实际上没有必要知道存在的值
比如:
//(尾递归)
<mark>尾递归可以通过将代码放到一个while循环中并用每个方法参数的一次赋值代替递归调用而被手工能消除。</mark>
//(尾递归)
public static <T> void printList(Iterator<T> itr){
if(!itr.hasNext()){
return ;
}
System.out.println(itr.next());
printList(itr);
}
- <mark>违反上面第四条法则</mark>
特别是: 在计算诸如“斐波那契数”之类简单数学函数的值得时候,用递归不是一个好注意。
例子如下:
https://blog.csdn.net/LawssssCat/article/details/103100980
大概的代码:↓↓↓
/** * 计算AVL树h高度时候,最小的节点数 * @param args */
public static void main(String[] args) {
int i = 50;
System.out.println(countHeight2(i));
System.out.println(countHeight(i));
}
/** * O(logN*2^N) * 不适合用递归的例子 * @param h * @return */
public static long countHeight(int h ) {
switch(h) {
case 0 : return 1 ;
case 1 : return 2 ;
default : return countHeight(h-1)+ countHeight(h-2) +1 ;
}
}
/** * O(n) * @param h * @return */
public static long countHeight2(int h ) {
switch(h) {
case 0 : return 1 ;
case 1 : return 2 ;
default :
long a0 = 1 ;
long a1 = 2 ;
long result = 0 ;
for(int i=1 ; i<h ; i++) {
result = a0 + a1 +1 ;
a0 = a1 ;
a1 = result ;
}
return result ;
}
}
前辈们的心得:
《为什么你学不会递归?告别递归,谈谈我的经验》
https://blog.csdn.net/m0_37907797/article/details/102767860