递归方法
在执行一个递归方法时就创建一个新的受保护的独立空间(栈空间)。递归必须向退出递归的条件逼近,否则就会无限递归(StackOverflowError),形成死递归。谁调用方法,结果返回给谁。
递归可以解决的问题
- 数学问题:8皇后问题,汉诺塔问题,阶乘,迷宫等。
- 各种算法中,如快速排序,归并排序,二分查找,分治算法等
迷宫问题
使用递归回溯方法,在一个迷宫中找出通路。
路径会根据寻找路径的策略不同而有所变化,策略不合适甚至会出现所有路径都走遍的问题。
public class FindPath {
public static void main(String[] args) {
//设置迷宫的地图,四周的墙壁和中间的墙壁
//使用二维数组表示迷宫地图,1表示墙壁,2表示通路径,3表示错误路,0表示未走路径
int map[][] = new int[10][9];
for(int i = 0;i<map.length;i++){
map[i][0]=1;
map[i][8]=1;
}
for(int j=0;j<map[1].length;j++){
map[0][j]=1;
map[9][j]=1;
}
map[3][1]=1;
map[3][2]=1;
map[3][4]=1;
System.out.println("原始迷宫地图");
for(int[] x:map){
for(int y:x){
System.out.print(y);
}
System.out.println();
}
findPath(map,1,1);
System.out.println("迷宫路径");
for(int[] x:map){
for(int y:x){
System.out.print(y);
}
System.out.println();
}
}
/*递归回溯方法寻找通路
map 当前迷宫地图,i,j为当前坐标
寻路策略为下,右,上,左
*/
public static boolean findPath(int[][] map, int i,int j){
if(map[8][7]==2){ //终点为map[8][7],若为2,说明路径找到
return true;
}else {
if(map[i][j]==0){
map[i][j]=2;
if(findPath(map,i+1,j)){
return true;
}else if(findPath(map,i,j+1)){
return true;
}else if(findPath(map,i-1,j)){
return true;
}else if(findPath(map,i,j-1)){
return true;
}else {
map[i][j]=3;
return false;
}
}else { // map[i][j]不为0,可能是1,2,3,
return false;
}
}
}
}
八皇后问题
在8×8的国际象棋棋盘上摆上8个皇后,任意两个不能处于同一行,同一列或者同一斜线上。求有多少中方法。
使用一维数组存放棋子的位置,索引数代表行数,值代表列数
按行摆棋子,只需判断当前摆放的棋子与之前摆放的是否在同一列或者同一斜线即可。
public class Queens8 {
private static int count=0;
private static int max=8;
private static int[] arr = new int[max];
public static void main(String[] args) {
check(0);
System.out.printf("共有%d种解法",count);
}
//找到一种完整解法,将其打印出来,并将解的个数加1
private static void print(){
for(int i:arr){
System.out.print(i+" ");
}
System.out.println();
count++;
}
//判断摆放的第N个棋子,即第N行上摆放的棋子与之前行上的棋子是否在同一列或斜线上
private static boolean judge(int n){
for(int i=0;i<n;i++){
if(arr[i]==arr[n] || Math.abs(n-i)==Math.abs(arr[n]-arr[i])){
return false;
}
}
return true;
}
//递归回溯 ,从第一行的棋子开始摆放,直到n==max即摆完8个棋子时结束递归
private static void check(int n){
if(n==max){ //逼近条件 n等于8 即代表第9行,说明前8行摆放完成符合要求
print();
return;
}
for(int i=0;i<max;i++){
arr[n]=i; //第行摆放棋子在第i列上
if(judge(n)){ //判断如果摆放的第n行棋子与之前的不冲突
check(n+1); //继续摆放第n+1行棋子
}
}
}
}
递归在使用的时候有时很好理解,但是对于资源的消耗很大,因为递归调用的方法都是压入虚拟机的栈中运行,如果递归的逼近条件没有处理好形成死递归造成栈溢出。