递归是一种方法调用自己的方式。在数学中的数列中这个是很普遍的,比如递推公式an = an_1 + 1
本章主要用递归来解决一些常见的问题。
1 三角数字
三角数字是这样的一个数字序列,1 3 6 10 15 21...
这个数字序列的规律是:a1 = 1,n >= 2时候,an = an_1 + n
方法1:使用递归循环查找第n项
我们可以看到第n项是1+2+3...+n的结果,所以可以用一个公式来计算
Sn = (1+n)*n/2
package chapter6; public class Demo01 { public static void main(String[] args){ int n = 5; int i = (1 + n)*n/2; System.out.println(i); } }
方法2:使用递归来解决
int triangle (int n){ return (n + triangle(n - 1)); } 代码: package chapter6; public class Demo01 { public static int triangle(int n){ if(n == 1){ return 1; }else{ return (n + triangle(n - 1)); } } public static void main(String[] args){ int i = Demo01.triangle(5); System.out.println(i); } }
递归和数学中的反复递推没有什么区别,但是需要注意的是一定要注意递归一定是有一个初始化的终点,不能无限递推下去。类似的阶乘也可以用递推方法来解决。
2 归并排序
可以利用递归来实现归并排序,归并排序比简单排序要快得多,冒泡、插入排序和选择排序要用O(N^2)时间,而归并排序只需要O(N*logN),如果排序的项目是10000,N^2 就是100000000,而N*logN只是40000,用归并排序是40秒,用插入排序是28个小时。归并排序的一个缺点是它需要在存储器重有另一个大小等于被排序的数据项目的数组,如果初始数组几乎占满整个存储器,那么归并排序将不能工作,但是如果有足够的空间,归并排序会是一个很好的选择。
2.1 归并两个有序数组
归并算法的中心是归并两个已经有序的数组,归并两个有序的数组A和B就生成了第三个数组C,C是有序的。下面考查排序过程。归并排序是很简单的。
假设有两个有序数组,不要求有相同的大小,设数组A有4个数据项,数组B有6个数据项。它们要被归并到数组C中,开始时数组C有10个空的存储空间。
A:2 7 27 33
B:1 7 8 23 24 77
C:
归并操作:
步骤 操作 复制 1 1和2比较 将1从B复制到C中 2 6和2比较 将2从A复制到C中 3 6和7比较 将6从B复制到C中 4 8和7比较 将7从A复制到C中 5 8和27比较 将8从B复制到C中 6 23和27比较 将23从B复制到C中 7 24和27比较 将24从B复制到C中 8 77和33比较 将33从A复制到C中 9 将77从B复制到C中
代码:
package chapter6; public class MergeApp { //归并排序算法 public static void merge(int[] arrayA, int[] arrayB, int[] arrayC){ int aDex = 0, bDex = 0, cDex = 0; while((aDex < arrayA.length)&&(bDex < arrayB.length)){ if(arrayA[aDex] < arrayB[bDex]){ arrayC[cDex++] = arrayA[aDex++]; }else{ arrayC[cDex++] = arrayB[bDex++]; } } //当B数组不存在时候,直接拷贝 while(aDex < arrayA.length){ arrayC[cDex++] = arrayA[aDex++]; } //当A数组不存在时候,直接拷贝B至C while(bDex < arrayB.length){ arrayC[cDex++] = arrayB[bDex++]; } } //输出数组 public static void display(int[] array){ for(int i:array){ System.out.print(i + " "); } System.out.println(); } public static void main(String[] args){ int[] arrayA = {2, 7, 27, 33}; int[] arrayB = {1, 7, 8, 23, 24, 77}; int[] arrayC = new int[10]; display(arrayA); display(arrayB); merge(arrayA, arrayB, arrayC); display(arrayC); } }
输出结果:
2 7 27 33
1 7 8 23 24 77
1 2 7 7 8 23 24 27 33 77
2.2 通过归并进行排序
归并排序的思想是把一个数组分成两半,排序每一半,然后用merge方法把两个数组的两半归并成一个有序数组。如何对每一部分进行排序呢?很简单,进行递归。把每一半再分成两个四分之一,再对每一个四分之一进行排序,如此再进行折半。
归并排序算法:
package sort; class DArray{ private long[] theArray; private int nElems; public DArray(int max){ theArray = new long[max]; nElems = 0; } //插入元素 public void insert(long value){ theArray[nElems++] = value; } //输出数组 public void display(){ for(long i:this.theArray){ System.out.print(i + " "); } System.out.println(); } //归并排序 public void mergeSort(){ //用于存放合并后的结果 long[] workSpace = new long[nElems]; recMergeSort(workSpace, 0, nElems - 1); } //通过递归方式对一个数组均分后排序 public void recMergeSort(long[] workSpace, int lowerBound, int upperBound){ //如果只有一个元素,不必排序,直接输出 if(lowerBound == upperBound){ return; }else{ int mid = (lowerBound + upperBound)/2; //排序均分后两段 recMergeSort(workSpace, lowerBound, mid); recMergeSort(workSpace, mid + 1, upperBound); //合并已经排序后的两段 merge(workSpace, lowerBound, mid + 1, upperBound); } } //合并分段排序结果的算法 public void merge(long[] workSpace, int lowPtr, int highPtr, int upperBound){ int j = 0; int lowerBound = lowPtr; int mid = highPtr - 1; int n = upperBound - lowerBound + 1; while(lowPtr <= mid && highPtr <= upperBound){ if(theArray[lowPtr] < theArray[highPtr]){ workSpace[j++] = theArray[lowPtr++]; }else{ workSpace[j++] = theArray[highPtr++]; } } while(lowPtr <= mid){ workSpace[j++] = theArray[lowPtr++]; } while(highPtr <= upperBound){ workSpace[j++] = theArray[highPtr++]; } for(j = 0; j < n; j++){ theArray[lowerBound + j] = workSpace[j]; } } }; public class MergeSortApp { public static void main(String[] args){ int maxSize = 10; DArray arr; arr = new DArray(maxSize); arr.insert(2); arr.insert(7); arr.insert(27); arr.insert(1); arr.insert(77); arr.insert(65); arr.display(); //进行归并排序 arr.mergeSort(); arr.display(); } };
输出结果:
2 7 27 1 77 65 0 0 0 0
1 2 7 27 65 77 0 0 0 0