递归:方法自己调用自己,不断地入栈出栈。
递归算法,其实说白了,就是程序的自身调用。它表现在一段程序中往往会遇到调用自身的那样一种coding策略,这样我们就可以利用大道至简的思想,把一个大的复杂的问题层层转换为一个小的和原问题相似的问题来求解的这样一种策略。这样我们就能看到我们会用很少的语句解决了非常大的问题,所以递归策略的最主要体现就是小的代码量解决了非常复杂的问题。
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
(皇后问题中使用了回溯的思想)
实现递归的三要素
1.方法中出现自己调用自己
2.要有分支
3.要有结束条件
一个简单的斐波那契数列的实现:
public class RecursionTest {
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n) {
if( n == 1 || n == 2) {
return 1;
}
return f(n-1)+ f(n-2);
}
}
注:递归中方法调用一直未结束,因此会占用大量内存。
迷宫问题:
import java.util.Arrays;
public class MiGong {
public static void main(String[] args) {
// 二维数组模拟迷宫
int[][] map = new int[8][7];
// 1表示墙,先把上下置为1
for (int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}
for (int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
}
map[2][2] = 1;
map[3][1] = 1;
map[3][2] = 1;
setWay(map, 1, 1, 6, 5);
}
public static void priMap(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
/**
* 走路规则:先朝下 走 不通 则朝右 不通则 朝上 ,不通则朝左 0表示还未走过得,1表示墙,2表示通路,可以走 3表示该路走过,但不通
*
* @param map 迷宫地图
* @param i (i,j)起始坐标
* @param j
* @param m (m,n)出口坐标
* @param n
*
* @return 是否可以走
*/
public static boolean setWay(int[][] map, int i, int j, int m, int n) {
if (map[m][n] == 2) {
priMap(map);
return true;
}
if (map[i][j] == 0) {
// 如果当前的这个点还没有走过且不是墙(走过就是2或者3)
map[i][j] = 2;// 假设这个点可以走
if (setWay(map, i + 1, j, m, n)) {
// 朝下走
return true;
} else if (setWay(map, i, j + 1, m, n)) {
// 朝右走
return true;
} else if (setWay(map, i - 1, j, m, n)) {
// 朝上走
return true;
} else if (setWay(map, i, j - 1, m, n)) {
// 朝左走
return true;
} else {
// 说明该点走不通,是死路
map[i][j] = 3;
return false;
}
} else {
// 该点为墙,或者已经走过,或者走不通
return false;
}
}
}
(不同的遍历规则可以走出不同的路,有不同的长度,把所有的规则遍历一个即可找到最短路径。)
N皇后问题:(问题是什么在此不再赘述)
import java.util.Arrays;
public class NQueen {
int max = 8;// 八皇后
int[] queen = new int[max]; // 记录皇后的位置
public static void main(String[] args) {
NQueen q = new NQueen();
q.nQueen(0);
}
/**
* n皇后问题 从第0行开始放置皇后,因此最初调用时n需传为0。放置一行之后,放置下一行……直至n位皇后放好。
*
* @param n表示第几行 (0~max-1)
* @return
*/
public void nQueen(int n) {
if (max == n) {
// 到max行,说明 max-1行已经成功放置皇后,又进入递归nQueen(max) 此时, 输出queen
System.out.println(Arrays.toString(queen));
// 回到调用位置(回溯,继续走下一列,看是否能成)
// 最后结束,则每一行每一列都试过
// 若要看一共有几个安放方法,只需在此count++即可
return;
}
for (int i = 0; i < max; i++) {
queen[n] = i;
if (judge(n)) {
//成立则递归,开始放置下一行的皇后
nQueen(n + 1);
}
}
}
/**
* 判断皇后位置是否正确(不同行,不同列,不同斜线(通过斜率判断))
* 不同行通过queen的不同下标实现
* @param n 当前放置的是第几行皇后(n-1)
* @return
*/
private boolean judge(int n) {
for (int i = 0; i < n; i++) {
if (queen[n] == queen[i] || Math.abs(n - i) == Math.abs(queen[n] - queen[i])) {
return false;
}
}
return true;
}
}