数据结构的Java实现(八)—— 递归

目录

例:斐波那契数列

例:有序数组的二分法查找

例:汉诺塔问题

 例:归并排序

例:背包问题


什么是递归?

 是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。


递归有三个要素:

  1. 有边界条件
  2. 有递归前进段
  3. 有递归返回段

当边界条件不满足时,递归前进;当边界条件满足时,递归返回。


递归(recursion)与迭代(iterate)的区别:

迭代是人,递归是神

递归是不断地深层调用函数,直到函数有返回才会逐层的返回。递归编程所体现的思想正是人们追求简洁、将问题交给计算机,以及将大问题分解为相同小问题从而解决大问题的动机。

迭代大部分时候需要人为的对问题进行剖析,将问题转变为一次次的迭代来逼近答案。迭代不像递归一样对堆栈有一定的要求,另外一旦问题剖析完毕,就可以很容易的通过循环加以实现。


例:斐波那契数列

package yrwan07;

import org.junit.Test;

/**
 * 递归的应用——斐波那契数列
 * 
 * @author Wyran
 *
 */
public class Fibonacci {
	@Test
	public void FibonacciTest() {
		System.out.println(getNumber(5));
	}

	public int getNumber(int n) {
		if (n == 0) {
			return 0;
		} else if (n == 1) {
			return 1;
		} else {
			return getNumber(n - 1) + getNumber(n - 2);
		}
	}
}

例:有序数组的二分法查找

package yrwan07;

import org.junit.Test;

/**
 * 递归的应用——二分法在有序数组中查找
 * 
 * @author Wyran
 *
 */
public class BinarySearch {
	@Test
	public void binarySearchTest() {
		int[] arr = { 10, 11, 12, 16, 18, 23, 29, 33, 48, 54, 57, 68, 77, 84, 98 };
		System.out.println(binarySearch(arr, 23, 0, arr.length - 1));
	}

	/**
	 * 
	 * @param arr 有序数组
	 * @param target 待查找值
	 * @param left 数组最小下标
	 * @param right 数组最大下标
	 * @return 待查值的下标
	 */
	public int binarySearch(int[] arr, int target, int left, int right) {
		int mid = (left + right) / 2;
		if (target == arr[mid]) {
			return mid;
		} else if (left > right) {
			return -1;
		} else {
			if (arr[mid] > target) {
				return binarySearch(arr, target, left, mid - 1);
			}
			if (arr[mid] < target) {
				return binarySearch(arr, target, mid + 1, right);
			}
		}
		return -1;
	}
}

例:汉诺塔问题

package yrwan07;

import org.junit.Test;

/**
 * 递归的应用——汉诺塔问题
 * 
 * @author Wyran
 *
 */
public class HanoiTower {
	@Test
	public void moveTest(){
		move(3, "A", "B", "C");
	}
	/**
	 * 
	 * @param num 移动的盘子数
	 * @param from 初始塔
	 * @param temp 中间塔
	 * @param to 目标塔
	 */
	public void move(int num, String from, String temp, String to) {
		if (num == 1) {
			System.out.println("将" + num + "号盘从" + from + "移动到" + to);
		} else {
			move(num - 1, from, to, temp);
			System.out.println("将" + num + "号盘从" + from + "移动到" + to);
			move(num - 1, temp, from, to);
		}
	}
}

 例:归并排序

package yrwan07;

import java.util.Arrays;

import org.junit.Test;

/**
 * 递归的应用——归并排序
 * 
 * @author Wyran
 *
 */
public class MergeSort {
	@Test
	public void mergeSortTest() {
		int[] arr = { 1, 8, 9, 6, 4, 3, 9, 15, -1 };
		int[] result = mergeSort(arr, 0, arr.length - 1);
		System.out.println(Arrays.toString(result));
	}
	
	/**
	 * 归并排序递归部分
	 * 
	 * @param arr 待排序数组
	 * @param left 开始排序的下标
	 * @param right 结束排序的下标
	 * @return 排序好的数组
	 */
	public int[] mergeSort(int[] arr, int left, int right) {
		if (left < right) {
			int mid = (left + right) / 2;
			mergeSort(arr, left, mid);
			mergeSort(arr, mid + 1, right);
			merge(arr, left, mid, right);// 合并
		}
		return arr;
	}
	
	/**
	 * 归并排序合并部分
	 * 
	 * @param arr 待排序数组
	 * @param left 左数组的开始下标
	 * @param mid 左数组的结束下标
	 * @param right 右数组的结束下标
	 */
	public void merge(int[] arr, int left, int mid, int right) {
		int[] temp = new int[right - left + 1];
		int i = left;// 左数组的开始下标
		int j = mid + 1;// 右数组的开始下标
		int num = 0;
		while (i <= mid && j <= right) {
			if (arr[i] < arr[j]) {
				temp[num++] = arr[i++];
			} else {
				temp[num++] = arr[j++];
			}
		}
		while (i <= mid) {
			temp[num++] = arr[i++];
		}
		while (j <= right) {
			temp[num++] = arr[j++];
		}

		for (int k = 0; k < temp.length; k++) {
			arr[k + left] = temp[k];
		}
	}
}

例:背包问题

package yrwan07;

/**
 * 递归的应用——背包问题
 * 
 * @author Wyran
 *
 */
public class Knapsack {
	private int[] weights; // 物品重量
	private boolean[] select;// 物品是否选择
	private boolean flag = false; // 结束递归的判断

	public Knapsack(int[] arr) {
		this.weights = arr;
		select = new boolean[arr.length];
	}

	/**
	 * 
	 * @param target 背包剩余可容纳重量
	 * @param index 尝试放入下标为index的物品
	 */
	public void knapsack(int target, int index) {
		if (flag) {
			return;
		}
		// 如果剩余可容纳为0则说明已成功
		if (target == 0) {
			flag = true;// 结束递归
			for (int i = 0; i < index; i++) {
				if (select[i] == true) {
					System.out.print(weights[i] + " ");
				}
			}
			return;
		}
		// 未找到方法
		if (target < 0 || index >= weights.length) {
			return;
		}
		// 进行递归

		// 尝试放入下标为index的物品
		select[index] = true;
		knapsack(target - weights[index], index + 1);
		// 下标为index的物品不满足则尝试下一个
		select[index] = false;
		knapsack(target, index + 1);
	}

	public static void main(String[] args) {
		int[] weights = { 11, 9, 7, 6, 5 };
		int target = 20;
		Knapsack knapsack = new Knapsack(weights);
		knapsack.knapsack(target, 0);
	}
}

 

/** * 根据等级查询类目树 * * @param level * @return */ @Override public List queryCategoryTree(Integer level) { //查询当前级别下类目 List list = categoryDAO.list(level); //组装好的类目树,返回前端 List categoryTree = new ArrayList(); //所有类目 List allDTOList = new ArrayList(); if (CollectionUtils.isEmpty(list)) { return categoryTree; } for (CategoryDO categoryDO : list) { allDTOList.add(new CategoryTreeDTO().convertDOToDTO(categoryDO)); } //当前等级类目 categoryTree = allDTOList.stream().filter(dto -> level.equals(dto.getLevel())).collect(Collectors.toList()); for (CategoryTreeDTO categoryTreeDTO : categoryTree) { //组装类目为树结构 assembleTree(categoryTreeDTO, allDTOList,Constants.CATEGORY_MAX_LEVEL - level); } return categoryTree; } /** * 组装树 * * @param categoryTreeDTO * @param allList * @param remainRecursionCount 剩余递归次数 * @return */ public CategoryTreeDTO assembleTree(CategoryTreeDTO categoryTreeDTO, List allList, int remainRecursionCount) { remainRecursionCount--; //最大递归次数不超过Constants.CATEGORY_MAX_LEVEL-level次,防止坏数据死循环 if(remainRecursionCount < 0){ return categoryTreeDTO; } String categoryCode = categoryTreeDTO.getCategoryCode(); Integer level = categoryTreeDTO.getLevel(); //到达最后等级树返回 if (Constants.CATEGORY_MAX_LEVEL == level) { return categoryTreeDTO; } //子类目 List child = allList.stream().filter(a -> categoryCode.equals(a.getParentCode())).collect(Collectors.toList()); if (null == child) { return categoryTreeDTO; } categoryTreeDTO.setChildren(child); //组装子类目 for (CategoryTreeDTO dto : child) { assembleTree(dto, allList,remainRecursionCount); } return categoryTreeDTO; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值