概述
递归是方法本身调用自己的一种算法。
由于java在调用方法时会在栈中开辟一个新的空间,所以递归一定要确定一个终止条件,且在不断递归的过程中,不断向这个条件靠近,否则会栈溢出。
也就是这个原因,有人说递归性能不好,内存占用大。
程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。 (百度百科)
图源:尚硅谷Java数据结构课程截图
java中执行代码时,每遇到一个方法,则在栈中压入此方法,执行时则从栈顶的方法开始执行,执行完必后此方法出栈,执行下一个方法。直到执行完成。
以上图举例:
执行main方法时,将main入栈,
开始执行main方法中的test(4),此时在栈中开辟一个test(4)的区域【n=4,判断4大于2,执行if中的语句test(3)】,
此时在栈中开辟一个test(3)的区域【n=3,判断4大于2,执行if中的语句test(2)】,
此时在栈中开辟一个test(2)的区域【n=4,判断2大于2false,不执行if内的语句,执行sout,输出n=2】,
执行完test(2),将其出栈再继续执行test(3)【此时test3执行完if中的语句,下一行代码输出n=3】,
执行完test(3),将其出栈再继续执行test(4)【此时test4执行完if中的语句,下一行代码输出n=4】,
执行完test(4),将其出栈再继续执行main【此时main执行完test4语句执行完毕】。
递归的作用
各种算法:快排、归并排序,二分查找、分治算法
将用栈解决的问题用递归解决,代码会更加简洁
递归一般用于解决三类问题:
(1)数据的定义是按递归定义的。(Fibonacci函数)
(2)问题解法按递归算法实现。
这类问题虽则本身没有明显的递归结构,但用递归求解比迭代求解更简单,如Hanoi问题。
(3)数据的结构形式是按递归定义的。
如二叉树、广义表等,由于结构本身固有的递归特性,则它们的操作可递归地描述。
(百度百科)
迷宫问题
此问题也可以用栈解决,但代码要麻烦很多。
用数组表示迷宫,1表示墙壁,2表示走迷宫的路径,3表示走过的死路
要从左上角以约定的方向优先级 走到迷宫的右下角
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
代码实现
package recursion;
public class MiGong {
public static void main(String[] args) {
int row = 7;
int col = 7;
int[][] map = new int[row][col];
for (int i = 0; i < map.length; i++) {
map[i][0] = 1;
map[i][col-1] = 1;
}
for (int i = 0; i < map[0].length; i++) {
map[0][i] = 1;
map[row-1][i] = 1;
}
map[3][1] = 1;
map[3][2] = 1;
map[3][3] = 1;
for (int[] ints : map) {
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println();
}
System.out.println("============");
setWay(map,1, 1);
for (int[] ints : map) {
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println();
}
}
public static boolean setWay(int[][] map, int i, int j){
if (map[5][5] == 2){
//表示已经到达右下角。
return true;
}
if (map[i][j] == 0){
//表示当前的位置可以走
map[i][j] = 2;
//约定一个方向的优先级,下-右-上-左 依次检查
if (setWay(map, i+1, j)){//向下走,看看能不能走通
return true;
}else if (setWay(map, i, j+1)){
//向右
return true;
}else if (setWay(map, i-1, j)){
//向上
return true;
}else if (setWay(map, i, j-1)){
//向左
return true;
}else {
//全部走不通
map[i][j] = 3;
return false;
}
}else {
return false;
}
}
}
八皇后问题
问题表述为:在8×8格的棋盘上摆放8个皇后,任意两个皇后都不能处于 同一行、同一列或同一斜线上,问有多少种摆法。
代码实现
package recursion;
public class Queen8 {
public static void main(String[] args) {
Queen8 queen8 = new Queen8();
queen8.put(0);
}
int[] result = new int[8];
//放置皇后,n表示这是第几个皇后
public void put(int n){
if (n == 8){
printQueen();
return;
}
for (int i = 0; i < 8; i++) {
result[n] = i;
if (judge(n)){
put(n+1);
}
}
}
//判断是否冲突,是否可以放置。false表示冲突,true表示不冲突,n表示这是第几个皇后
public boolean judge(int n){
for (int i = 0; i < n; i++) {
if (result[i] == result[n]
|| Math.abs(i-n) == Math.abs(result[i]-result[n])){
//冲突
return false;
}
}
return true;
}
public void printQueen(){
for (int i : result) {
System.out.print(i);
}
System.out.println();
}
}