一、递归的定义
递归就是在运行的过程中调用自己。
递归必须要有三个要素:
- 边界条件
- 递归前进段
- 递归返回段
当边界条件不满足时,递归前进;当边界条件满足时,递归返回
二、求阶乘
package recursion;
import java.util.Scanner;
public class RecursionTest1 {
public static void main(String[] args) {
//提示
System.out.println("请输入一个整数:");
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//调用一个方法,获取n!
int rs = getFactoriaFor(n);
System.out.println("n!是: " + rs);
}
//通过循环实现n!
public static int getFactoriaFor(int n) {
if (n >= 0) {
int tmp = 1;
for (int i = 1; i <= n; i++) {
tmp = tmp * i;
}
return tmp;
} else {
return -1; //负数没有阶乘
}
}
//通过递归的算法实现n!
public static int getFactorialRecursion(int n) {
if (n >= 0) {
if (n == 0) {
return 1;
} else {
int tmp = n * getFactorialRecursion(n - 1);
return tmp;
}
} else {
return -1;
}
}
}
三、求数字三角形的最大路径值
package recursion;
import java.util.Scanner;
/**
* 数字三角形最大路径计算
* 1
* 2 3
* 4 5 6
*/
public class RecursionTest2 {
private static int[][] data; //存放数字三角形的数字
private static int n; //三角形的行数
public static void main(String[] args) {
//二维数组的初始化
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字三角形的高度:");
n = sc.nextInt();
//实例化二维数组
data = new int[n][n];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
System.out.println("请输入第" + i + "行,第" + j + "列的数字");
data[i-1][j-1] = sc.nextInt();
}
}
System.out.println("--------------数字三角形------------");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(data[i-1][j-1] + " ");
}
System.out.println();
}
System.out.println("-------------测试结果--------------");
int rs;
rs = maxSum(1, 1);
System.out.println("结果为:" + rs);
}
public static int maxSum(int i, int j) {
if (i == n) { //边界条件
return data[i-1][j-1];
} else {
int x = maxSum(i + 1, j);
int y = maxSum(i + 1, j + 1);
return Math.max(x, y) + data[i - 1][j - 1];
}
}
}
四、递归实现二分查找
分治算法简介:
当我们求解某些问题时,由于这些问题要处理的数据非常多,或求解过程非常复杂,我们往往先把它分解成几个子问题,找到求出这几个自问题的方法后,再找到合适的方法合成求整个问题的解法。如果这几个子问题还比较大,可以将它们再分成更小的子问题,以此类推,直到可以求解为止,这就是分治策略的基本思想。
二分查找就是一个典型的例子,将查找范围分查比查找值大的一部分和比查找值小的一部分,每次递归调用只会有一个部分执行。
package recursion;
public class RecursionTest3 {
public static void main(String[] args) {
int[] arr = {1,2,4,6,7,8,9};
int rs;
rs = binarySearchRecursion(arr,7,0,6);
System.out.println(rs);
}
public static int binarySearchRecursion(int[] arr, int value, int l, int h) {
int mid = (h + l) / 2;
if (value == arr[mid]) {
return mid;
} else if (l > h) {
return -1;
} else {
if (value > arr[mid]) {
return binarySearchRecursion(arr, value, mid + 1, h);
}
if (value < arr[mid]) {
return binarySearchRecursion(arr, value, l, mid - 1);
}
}
return -1;
}
//for循环实现二分查找
public static int binarySearchfor(int[] array, int value) {
int low = 0;
int high = array.length-1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (value == array[mid]) {
return mid;
} else {
if (value > array[mid]) {
low = mid + 1;
}
if (value < array[mid]) {
high = mid - 1;
}
}
}
return -1; //数组中不存在我们要找的值
}
}
五、汉诺塔
package recursion;
public class RecursionTest4 {
public static void main(String[] args) {
move(3,"A","B","C");
}
public static void move(int dish, String from, String tmp, String to) {
if (dish == 1) {
System.out.println("将第" + dish + "个盘子从" + from + "移动到目标塔座" + to);
} else {
move(dish - 1, from, to, tmp);
System.out.println("将第" + dish + "个盘子从" + from + "移动到目标塔座" + to);
move(dish - 1, tmp, from, to);
}
}
}
六、归并排序
package recursion;
import java.util.Arrays;
public class RecursionTest6 {
public static void main(String[] args) {
int[] rs = mergeSort(new int[] {3, 2, 1}, 0, 2);
System.out.println(Arrays.toString(rs));
}
//实现归并排序
public static int[] mergeSort(int[] c, int l, int h) {
if (l >= h) {
} else {
int mid = (l + h) / 2;
mergeSort(c, l, mid);
mergeSort(c, mid + 1, h);
//把分出来的子数组归并
merge(c, l, mid, h);
}
return c;
}
//实现子数组合并
public static void merge(int[] c, int l, int mid, int h) {
int i = l;
int j = mid + 1;
int[] tmp = new int[h - l + 1];
int k = 0;
//实现合并
while (i <= mid && j <= h) {
if (c[i] < c[j]) {
tmp[k++] = c[i++];
} else {
tmp[k++] = c[j++];
}
}
while (i <= mid && j > h) {
tmp[k++] = c[i++];
}
while (i > mid && j <= h) {
tmp[k++] = c[j++];
}
for (int g = 0; g < tmp.length; g++) {
c[l + g] = tmp[g];
}
}
}
七、用栈消除递归
package recursion;
import java.util.Stack;
public class RecursionTest7 {
public static void main(String[] args) {
System.out.println(addn(3));
System.out.println(addn1(3));
}
//求1+2+3+...+n的值,递归
public static int addn(int n) {
if (n == 1) {
return n;
}else {
return n + addn(n - 1);
}
}
//消除递归,依靠栈来消除
public static int addn1(int n) {
Stack<Params> stack = new Stack<>();
int currentReturnValue = 0;
int currentReturnAddress = 1;
Params params = null;
boolean flag = true;
while (flag ) {
switch (currentReturnAddress) {
//初始的参数封装为Params对象,压入栈,设置一下走的分支地址是第二分支
case 1:
params = new Params(n, 6);
stack.push(params);
currentReturnAddress = 2;
break;
//模拟递归算法的边界条件,满足边界条件,把值赋给currentReturnValur,设定下一跳为5,否则设定下一条为3
case 2:
params = stack.peek();
if (params.getN() == 1) {
currentReturnValue = params.getN();
currentReturnAddress = 5;
}else {
currentReturnAddress = 3;
}
break;
//模拟递归,n-1作为新的参数压入栈,参数对象返回地址4,设置下一跳:2
case 3:
params = stack.peek();
params = new Params(params.getN()-1,4);
stack.push(params);
currentReturnAddress = 2;
break;
//将栈中的参数对象取出,将要获得的值做叠加操作,跳转步骤5
case 4:
params = stack.peek();
currentReturnValue += params.getN();
currentReturnAddress = 5;
break;
//把前面第四分支已经叠加过的参数,从栈中删除,如果栈中的参数删除完了,根据参数对象的返回地址,设定下一跳地址
case 5:
params = stack.pop();
currentReturnAddress = params.getReturnAddress();
break;
//完成运算,结束while循环,等同于递归完毕
case 6:
flag = false;
}
}
return currentReturnValue;
}
}
//写一个封装参数的类
class Params{
private int n;
private int returnAddress; //返回地址
public Params(int n, int address) {
this.n = n;
this.returnAddress = address;
}
public void setN(int n) {
this.n = n;
}
public void setReturnAddress(int returnAddress) {
this.returnAddress = returnAddress;
}
public int getN() {
return n;
}
public int getReturnAddress() {
return returnAddress;
}
}
八、求一个数的乘方
package recursion;
/**
* 计算一个数的乘方
*/
public class RecursionTest8 {
public static void main(String[] args) {
System.out.println(pow(2,6));
}
//递归方法
public static int pow(int x, int y) {
if (y == 0) {
return 1;
}
if (y == 1) {
return x;
}
if (y % 2 == 1) {
return pow(x * x,y/2) * x;
}else {
return pow(x * x, y / 2);
}
}
}
九、背包问题
package recursion;
public class RecursionTest9 {
public static void main(String[] args) {
int[] arr = new int[]{11, 8, 7, 6, 5};
Knapsack knapsack = new Knapsack(arr);
knapsack.doKnapsack(22,0);
}
}
//解决背包问题的类
class Knapsack{
private int[] data; //用来被选择的数据项组成的数组
private boolean[] selects; //这个数组和上面的数组的长度是一样的,true表示被选中
//初始化上面的属性
public Knapsack(int[] data) {
this.data = data;
selects = new boolean[data.length];
}
//解决背包问题的方法
public void doKnapsack(int aim, int index) {
//边界条件
if (aim != 0 && index >= data.length) {
return; //所有的组合都测试了,没有找到
}
if (aim == 0) { //找到了
for (int i = 0; i < selects.length; i++) {
if (selects[i]) {
System.out.print(data[i] + " ");
}
}
System.out.println();
return;
}
selects[index] = true;
doKnapsack(aim-data[index],index+1);
selects[index] = false;
doKnapsack(aim,index+1); //上面的数据放进背包里对应的所有的组合都不对,从下一个数据项重来
}
}
十、组合问题
package recursion;
public class RecursionTest10 {
public static void main(String[] args) {
char[] arr = new char[]{'A', 'B', 'C', 'D', 'E'};
Comb comb = new Comb(arr);
comb.doComb(3,0);
}
}
class Comb{
private char[] persons;
private boolean[] selects;
public Comb(char[] data) {
this.persons = data;
selects = new boolean[data.length];
}
//具体实现组合的递归方法
public void doComb(int selectNum, int index) {
//边界
if (selectNum == 0) { //找到
for (int i = 0; i < selects.length; i++) {
if (selects[i]) {
System.out.print(persons[i] + " ");
}
}
System.out.println();
return;
}
if (index >= persons.length) { //所有的组合都找完了
return;
}
selects[index] = true;
doComb(selectNum - 1, index + 1);
selects[index] = false;
doComb(selectNum,index+1);
}
}
当发现递归的效率比较低时,我们可以尝试用循环或者栈来代替它