一、递归的应用场景
二、递归的调用机制
简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。
①解析
②递归要遵守的规则
③代码:
package com.ws.递归.递归的尝试;
public class Test {
public static void main(String[] args) {
//递归的调用机制测试
System.out.println("递归减法:");
di(4);
System.out.println("递归阶乘:");
System.out.println(jiecheng(3));
}
//递归
public static void di(int n){
if (n>2){
di(n-1);
}
System.out.println("n="+n);
}
//阶乘
public static int jiecheng(int n){
if (n==1){
return 1;
}else {
return jiecheng(n-1)*n;
}
}
}
//输出:
递归减法:
n=2
n=3
n=4
递归阶乘:
6
三、递归用于解决什么问题
四、迷宫问题
①找出路径
package com.ws.递归.迷宫问题;
public class MiGong {
public static void main(String[] args) {
//创建一个二维数组,模拟迷宫
//地图
int[][] map=new int[8][7];//8行7列迷宫
//上下全置1模拟墙
for (int i=0;i<7;i++){
map[0][i]=1;
map[7][i]=1;
}
//左右全置1
for (int i=0;i<8;i++){
map[i][0]=1;
map[i][6]=1;
}
//设置挡板
map[3][1]=1;
map[3][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();
}
//递归找路
getLu(map,1,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();
}
}
//使用递归回溯给小球找路
//出发点:(1,1)
//找到结束点:(6,5)
//当map[i][j]= 0时表示没有走过 1时表示墙,不能走 2时表示可以走 3时表示探过路了,走不通
//探测策略:下->右->上->左 该点走不通,回溯
/*
* map:地图
* i,j:从哪个位置开始找
* 找到返回true 否则false
* */
public static boolean getLu(int[][] map,int i,int j){
if (map[6][5]==2){//已经走通
return true;
}else {
if (map[i][j]==0){//当前点没走过
//按照策略走 下->右->上->左 该点走不通,回溯
map[i][j]=2;//假定该点可走通
if (getLu(map,i+1,j)){//向下走能走通
return true;
}else if (getLu(map,i,j+1)){//向下走不通就向右走
return true;
}else if (getLu(map,i-1,j)){//下右走不通就向上走
return true;
}else if (getLu(map,i,j-1)){//下右上走不通就向左走
return true;
}else {//上下左右都走不通,说明这个点根本走不通
map[i][j]=3;//表示这一个点探过了,走不通
return false;
}
}else {//如果map[i][j]不等于0 则可能是 1 2 3表示走过的,包括可以走,不能走,和死路
return false;//不通就回去上一个点
}
}
}
}
②找出最短路径
四种寻找方式都试一遍
package com.ws.递归.迷宫问题.最短路径;
public class MiGong {
public static void main(String[] args) {
//创建一个二维数组,模拟迷宫
//地图
int[][] map=new int[8][7];//8行7列迷宫
//上下全置1模拟墙
for (int i=0;i<7;i++){
map[0][i]=1;
map[7][i]=1;
}
//左右全置1
for (int i=0;i<8;i++){
map[i][0]=1;
map[i][6]=1;
}
//设置挡板
map[3][1]=1;
map[3][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();
}
//递归找路
getLu(map,1,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();
}
//最短路径,通过策略改变找
//一直改变策略
System.out.println("这种策略的最短路径长是:"+getMinimum(map));
}
//使用递归回溯给小球找路
//出发点:(1,1)
//找到结束点:(6,5)
//当map[i][j]= 0时表示没有走过 1时表示墙,不能走 2时表示可以走 3时表示探过路了,走不通
//探测策略:上->右->下->左 该点走不通,回溯
/*
* map:地图
* i,j:从哪个位置开始找
* 找到返回true 否则false
* */
public static boolean getLu(int[][] map,int i,int j){
if (map[6][5]==2){//已经走通
return true;
}else {
if (map[i][j]==0){//当前点没走过
//按照策略走 上->右->下->左 该点走不通,回溯
map[i][j]=2;//假定该点可走通
//是四种策略:
if (getLu(map,i-1,j)){//向上走能走通
return true;
}else if (getLu(map,i,j+1)){//向上走不通就向右走
return true;
}else if (getLu(map,i+1,j)){//上右走不通就向下走
return true;
}else if (getLu(map,i,j-1)){//上右下走不通就向左走
return true;
}else {//上下左右都走不通,说明这个点根本走不通
map[i][j]=3;//表示这一个点探过了,走不通
return false;
}
}else {//如果map[i][j]不等于0 则可能是 1 2 3表示走过的,包括可以走,不能走,和死路
return false;//不通就回去上一个点
}
}
}
//最短路径
//我们就在这用3中策略吧,因为策略太多了,不一一举例了,我们就求这三种策略谁的路径短
//求最短路径方法
public static int getMinimum(int[][] map){
int count = 0;//用来存储通路多长
//遍历map
for (int i = 0; i <8 ; i++) {
for (int j = 0; j <7 ; j++) {
if (map[i][j] == 2){
count++;
}
}
}
return count;
}
}
结果
地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
输出路线
1 1 1 1 1 1 1
1 2 2 2 2 2 1
1 0 0 0 0 2 1
1 1 1 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 1 1 1 1 1 1
这种策略的最短路径长是:10
五、八皇后问题
①问题介绍
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
②问题解决思路
③代码
package com.ws.递归.八皇后问题;
public class Queue8 {
//表示有几个皇后
int max=8;
//定义数组。保存皇后的位置
int[] array=new int[max];
static int count=0;//解法共有多少种
static int ifCount=0;//判断多少次
public static void main(String[] args) {
//测试
System.out.println("8皇后解法共有:");
Queue8 queue8 = new Queue8();
queue8.huanghou(0);
System.out.println("共有"+count+"种解法");
System.out.printf("一共判断【%d】次",ifCount);
}
//打印皇后位置
private void print(){
System.out.print("第"+count+"种:");
for (int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
//判断是否符合规定,就是不能同一行,同一列,对角线
private boolean ifkefang(int n){//放第n个皇后
ifCount++;//判断多少次
for (int i=0;i<n;i++){
// 同一列 对角线
if (array[i]==array[n]||Math.abs(n-i)==Math.abs(array[n]-array[i])){
return false;
}
}
return true;
}
//放置皇后,就是一行从第一个开始放
//每行一个皇后
//n是第几行<==>第几个皇后
private void huanghou(int n){
if (n==max){//放第九个皇后,8个放完了
count++;
print();
return;
}
//没有就依次放皇后,判断是否冲突
for (int i=0;i<max;i++){
//当前皇后放该行的第i列 i是第几列
array[n]=i;
//判断第几行(第几个皇后)的第几列是否冲突
if (ifkefang(n)){//第n行(n个皇后)不冲突
//接着放第n+1行(个皇后),开始递归
huanghou(n+1);
}
}
}
}