递归
递归 recursion
递归方法就是 自己调用自己,而且每次都传不同的变量。
1.递归要干什么?
2.递归停止的条件是什么?
3.从本层到下层的关系是什么?
调用机制
- 先自己调用自己,不断在栈中开辟空间;
- 到达最顶层后,函数运行完毕,销毁,转到后一个函数;
- 直到到达 main栈,没有方法了 退出程序。
应用场景:
- 各种数学问题:8皇后问题,汉诺塔,阶乘,迷宫,球和篮子问题等等;
- 各种算法:快排,归并,二分查找,分治法等等;
- 各种 用栈解决的问题(用递归使代码更简洁)。
遵守重要规则:
- 每执行一个方法,即创建一个新的受保护的独立空间(栈空间)
- 方法中的 局部变量是独立的
- 若方法中 使用的是 引用类型变量(数组等),就会共享该数据
- 递归必须向 退出递归的条件逼近,否则无限递归 StackOverflowErrow栈溢出
- 当一个方法执行完毕 或 遇到return,就会返回,遵循谁调用返回谁。
迷宫问题
题目:
迷宫中有边界,有挡板,需要从起点位置(<1,1>--<6,5>) 到达终点。
初始化地图
/* recursion-迷宫问题
1. 数组 map 表示地图
2. i,j 表示 当前出发的位置
3. 若小球能到达 map[x-1][y-1]位置,说明通路找到;
4. 约定当map[i][j]
为0 表示没走过 ,
为1 表示为墙 ,
为2 表示通路,可以走
为3 表示走过,走不通
5. 确定一个走的策略(可以自己定): 下->右->上->左
*/
public static void main(String[] args) {
int[][] map = new int[8][7];
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[3][1] = 1; //挡板
map[3][2] = 1;
map[2][2] = 1;
map[1][2] = 1;
System.out.println("原图情况:");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}
boolean isOk = setWay(map,1,1);
System.out.println(isOk+" 走过后情况:");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}
}
代码实现:
-
判断 当前位置是否已到达终点,
-
没到终点,不断 递归选路:
/** * 2.找路 (自己定义 上左下右的 顺序) * @param map 表示地图 * @param i 表示当前位置 * @param j * @return 找到通路返回true,否则返回false */ public static boolean setWay(int[][] map,int i,int j){ //1.判断是否到达终点 int x = map.length; int y = map[0].length; if (map[x-2][y-2]==2){ //找到终点,直接返回 return true; }else { //2.未到终点,不断递归寻路 if (map[i][j]==0){ //a.若当前点 未走过 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 { //b.当前点走过了 false return false; } } }
八皇后问题
8X8的棋盘,每一行一个棋子,每个棋子 不能在同一列,不能在同一斜线。
思路:前7个放好,放第8列-->回溯到前6个放好,放第7,8列 。。。
- 第一个皇后先放在第一行的第一列
- 第二个皇后放在第二行的第一列,判断是否冲突,否则放在 第2,3..8列
- 直到第八个皇后的位置放好,回溯到上一个皇后 放到另一列
- 直到第一个皇后 放到最后一列,所有情况都遍历完毕。
代码:
- 初始化数组
- judge(n) 判断当前行 放置后 是否与前面冲突【n为当前行 的 列的位置】
- check(0) 第0行开始 放皇后,遍历每一列,递归到下一行继续遍历。
8皇后问题代码实现
class Queue8{
/* 八皇后问题
有8个栈(8行 check),
每个栈 中都会有8次循环【列的位置】, 列judge正确就 进入下一个栈
第8行判断完后直接return,回到上一栈
8次循环完毕后 返回上一个栈
*/
//1.创建一个 一维数组,表示皇后的位置
public int max = 8;
public int[] arr = new int[max]; //arr[i]=value -->i表示第几行,value表示第几列
public static int count; //记录轮数:即共有多少中放法
public static int judgeCount; //记录判断次数
//2.检测 放的第n个皇后是否与前面的冲突
public boolean judge(int n){
judgeCount++;//判断次数
//遍历前面的行
for (int i = 0; i < n; i++) {
boolean isCol = arr[i]==arr[n]; //同一列
boolean isDiagonal = Math.abs(n-i)==Math.abs(arr[n]-arr[i]); //同一对角线
if (isCol || isDiagonal){
return false;
}
}
return true; //不冲突返回true
}
//3.放皇后
public void check(int n){
if (n == max){ //遍历到了第9行,此轮放完了
++count;
print();
return;
}
//1.遍历每一列
for (int i = 0; i < max; i++) {
arr[n] = i; //假设此列能放
if (judge(n)){ //注意这里传n 行数,而不是i
check(n+1); //此列能放,进入下一行
}
}
}
//打印数组
public void print(){
for (int i = 0; i < max; i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
Queue8 queue8 = new Queue8();
queue8.check(0);
System.out.printf("共有%d种结果\n",count);
System.out.printf("共判断了%d次",judgeCount);
}
}
我是菜鸡啊
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现