对递归进行优化–剪枝
上文讲述了递归的一个优化手段:记忆化。
本文将讲述递归的另一个优化手段:剪枝。
如前文所述,递归的一个缺点是执行步数或者说路径狠长,导致运行时间长。
那么有没有什么办法减少执行次数呢?
剪枝就是这么一个手段。
当在递归过程中,已经明确知道当前不会是最优解,或者说再往下走不会得到正确结果,则可以不再往下递归,从而减少执行次数。
下面以一个示例来进行演示如何进行剪枝。
示例:任意输入10个数,从这10个数中任取8个数(不重复)并求和,求和的最小值。
比如:10个数为1 2 3 4 5 6 7 8 9 10,则最小和为36 (即1+2+3+4+5+6+7+8).
先用不剪枝的递归来实现:
package hello;
import java.util.Scanner;
public class Hello {
static int count=0; //递归调用的次数
static int mmin=Integer.MAX_VALUE; //最小的和
boolean s[]=new boolean[10]; //标记某个数是否被使用过
//不剪枝的递归
void bujz(int[] a,int ci,int sum){
count++; //计算递归调用的次数
if(ci==8){ //已经达到8个数,递归结束
if(sum<mmin){ //如果比当前的mmin小,则更新mmin
mmin=sum;
}
return ;
}
for(int i=0;i<10;i++){
if(s[i]==false){
s[i]=true; //标记是否使用过
bujz(a,ci+1,sum+a[i]); //累加和,次数加1,并递归调用
s[i]=false;
}
}
return ;
}
public static void main(String[] args) {
int a[]=new int[10];
Scanner sc=new Scanner(System.in);
for(int i=0;i<10;i++){
a[i]=sc.nextInt();
}
Hello h=new Hello();
h.bujz(a,0,0); //不剪枝
System.out.println("最小的和为:"+mmin+",次数:"+count);
}
}
程序运行结果:
从运算结果可以看到: 递归调用了 260万次。
下面我们用剪枝来优化一下:
package hello;
import java.util.Scanner;
public class Hello {
static int count=0; //递归调用的次数
static int mmin=Integer.MAX_VALUE; //最小的和
boolean s[]=new boolean[10]; //标记某个数是否被使用过
//剪枝的递归,可以减少递归调用的次数
void jz(int[] a,int ci,int sum){
count++; //计算递归调用的次数
//下面这个if语句,完成剪枝
if(sum>=mmin){ //在未达到8个数之前,和已经大于mmin,没有必要再往下递归了
return ;
}
if(ci==8){
mmin=sum;
return ;
}
for(int i=0;i<10;i++){
if(s[i]==false){
s[i]=true;
jz(a,ci+1,sum+a[i]);
s[i]=false;
}
}
return ;
}
public static void main(String[] args) {
int a[]=new int[10];
Scanner sc=new Scanner(System.in);
for(int i=0;i<10;i++){
a[i]=sc.nextInt();
}
Hello h=new Hello();
h.jz(a,0,0); //剪枝
System.out.println("最小的和为:"+mmin+",次数:"+count);
}
}
从运算结果可以看到: 递归调用了 107万次。
减少了50%多的运行次数,效果还是很可观的。
这个剪枝的技巧,在递归中经常被使用,可以明显提高递归效率。
大家可以在以后的开发过程中尝试使用。
源码、更多资深讲师相关课程资料、学习笔记请入群后向管理员免费获取,更有专业知识答疑解惑。入群即送价值499元在线课程一份。
QQ群号:560819979
敲门砖(验证信息):高山流水