1、三角数字
// to run this program: C>java TriangleApp
import java.io.*;class TriangleApp
{
static int theNumber;
public static void main(String[] args) throws IOException
{
System.out.print("Enter a number: ");
theNumber = getInt();
int theAnswer = triangle(theNumber);
System.out.println("Triangle="+theAnswer);
}
public static int triangle(int n)
{
if(n==1)
return 1;
else
return ( n + triangle(n-1) );
}
public static String getString() throws IOException
{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
public static int getInt() throws IOException
{
String s = getString();
return Integer.parseInt(s);
}
}
2、全排列
doAnagram(10):对于10个字符串的数组,选择第一个字符后,对后面的9个字符doAnagram(9),数组中字符再左移一个单位,再对后面的9个字符doAnagram(9)。也就是doAnagram(10)分为10个doAnagram(9),1个doAnagram(9)分为9个doAnagram(8),...,1个doAnagram(2)分为2个doAangram(1),doAnagram(1)则返回空,返回空后再打印。
// to run this program: C>java AnagramApp import java.io.*; class AnagramApp { static int size; static int count; static char[] arrChar = new char[100]; public static void main(String[] args) throws IOException { System.out.print("Enter a word: "); String input = getString(); size = input.length(); count = 0; for(int j=0; j<size; j++) arrChar[j] = input.charAt(j); doAnagram(size); } public static void doAnagram(int newSize) {if(newSize == 1) return; for(int j=0; j<newSize; j++) { doAnagram(newSize-1); if(newSize==2) displayWord(); rotate(newSize); } }
public static void rotate(int newSize) { int j; int position = size - newSize; char temp = arrChar[position]; for(j=position+1; j<size; j++) arrChar[j-1] = arrChar[j]; arrChar[j-1] = temp; } public static void displayWord() { System.out.print(++count + "、"); for(int j=0; j<size; j++) System.out.print( arrChar[j] ); System.out.println(""); } public static String getString() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return s; } }
3、二分查找
// to run this program: C>java BinarySearchAppclass ordArray
{
private long[] a;
private int nElems;
public ordArray(int max)
{
a = new long[max];
nElems = 0;
}
public int size()
{ return nElems; }
public int find(long searchKey)
{
return recFind(searchKey, 0, nElems-1);
}
private int recFind(long searchKey, int lowerBound,int upperBound)
{
int curIn;
curIn = (lowerBound + upperBound ) / 2;
if(a[curIn]==searchKey)
return curIn;
else if(lowerBound > upperBound)
return nElems;
else
{
if(a[curIn] < searchKey)
return recFind(searchKey, curIn+1, upperBound);
else
return recFind(searchKey, lowerBound, curIn-1);
}
}
public void insert(long value)
{
int j;
for(j=0; j<nElems; j++)
if(a[j] > value)
break;
for(int k=nElems; k>j; k--)
a[k] = a[k-1];
a[j] = value;
nElems++;
}
public void display()
{
for(int j=0; j<nElems; j++)
System.out.print(a[j] + " ");
System.out.println("");
}
} class BinarySearchApp
{
public static void main(String[] args)
{
int maxSize = 100;
ordArray arr;
arr = new ordArray(maxSize);
arr.insert(72);
arr.insert(90);
arr.insert(45);
arr.insert(126);
arr.insert(54);
arr.insert(99);
arr.insert(144);
arr.insert(27);
arr.insert(135);
arr.insert(81);
arr.insert(18);
arr.insert(108);
arr.insert(9);
arr.insert(117);
arr.insert(63);
arr.insert(36);
arr.display();
int searchKey = 27;
if( arr.find(searchKey) != arr.size() )
System.out.println("Found " + searchKey);
else
System.out.println("Can't find " + searchKey);
}
}
4、分治算法
递归的二分查找是分治算法的一个例子。把一个大问题分成两个相对来说更小的问题,并且解决每一个子问题。对每一个小问题的解决方法是一样的:把每个小问题分成两个更小的问题,并且解决它们。这个过程一直持续下去直到达到易于求解的基值情况,就不用再继续分了。
分治算法常常是一个方法,在这个方法中含有两个对自身的递归调用,分别对应于问题的两个部分。在二分查找中,就有两个这样的调用,但是只有一个真的执行了。后面的归并排序是真正执行了两个递归调用。
5、汉诺塔
三个塔A,B,C。盘子最开始在A,从上到下,一次编号1,2,3,4..,编号越大,盘子越大,最有要搬到C盘子上,从上到下,盘子依次变大
// to run this program: C>java TowersAppclass TowersApp
{
static int nDisks = 5;
public static void main(String[] args)
{
doTowers(nDisks, 'A', 'B', 'C');
}
public static void doTowers(int topN, char src, char inter, char dest)
{
if(topN==1)
System.out.println("Disk 1 from " + src + " to "+ dest);
else
{
doTowers(topN-1, src, dest, inter);
System.out.println("Disk " + topN +" from " + src + " to "+ dest);
doTowers(topN-1, inter, src, dest);
}
}
}
6、归并两个数组
// to run this program: C>java MergeAppclass MergeApp
{
public static void main(String[] args)
{
int[] arrayA = {23, 47, 81, 95};
int[] arrayB = {7, 14, 39, 55, 62, 74};
int[] arrayC = new int[10];
merge(arrayA, 4, arrayB, 6, arrayC);
display(arrayC, 10);
}
public static void merge( int[] arrayA, int sizeA,
int[] arrayB, int sizeB,
int[] arrayC )
{
int aDex=0, bDex=0, cDex=0;
while(aDex < sizeA && bDex < sizeB)
if( arrayA[aDex] < arrayB[bDex] )
arrayC[cDex++] = arrayA[aDex++];
else
arrayC[cDex++] = arrayB[bDex++];
while(aDex < sizeA)
arrayC[cDex++] = arrayA[aDex++];
while(bDex < sizeB)
arrayC[cDex++] = arrayB[bDex++];
}
public static void display(int[] theArray, int size)
{
for(int j=0; j<size; j++)
System.out.print(theArray[j] + " ");
System.out.println("");
}
}
7、归并排序
归并排序的思想是把一个数组分成两半,每一半再分成两半,一直到不能分为止,然后用merge()方法把的每两半归并成一个有序的数组。一直归并下去。
一个问题分成两个子问题,每个子问题又分成两个子问题,一直到易于求解的基值为止,再对每两个子问题归并排序,这是这两个子问题求解,再去求解子问题的父问题。
运行时间:O(N*logN)。需要一个大小与原来数组相等的工作空间
// to run this program: C>java MergeSortApp 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; nElems++; } public void display() { for(int j=0; j<nElems; j++) System.out.print(theArray[j] + " "); System.out.println(""); } public void mergeSort() { long[] workSpace = new long[nElems]; recMergeSort(workSpace, 0, nElems-1); } private 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, upperBound); } } private void merge(long[] workSpace, int lowerBound,int mid, int upperBound) { int j = 0; int n = upperBound-lowerBound+1; int lowerPtr = lowerBound; //lower那个数组的下标 int upperPtr = mid+1; //upper那个数组的下标 while(lowerPtr<= mid && upperPtr <= upperBound) if( theArray[lowerPtr] < theArray[upperPtr] ) workSpace[j++] = theArray[lowerPtr++]; else workSpace[j++] = theArray[upperPtr++]; while(lowerPtr <= mid) workSpace[j++] = theArray[lowerPtr++]; while(upperPtr <= upperBound) workSpace[j++] = theArray[upperPtr++]; for(j=0; j<n; j++) theArray[lowerBound+j] = workSpace[j]; } } class MergeSortApp { public static void main(String[] args) { int maxSize = 100; DArray arr; arr = new DArray(maxSize); arr.insert(64); arr.insert(21); arr.insert(33); arr.insert(70); arr.insert(12); arr.insert(85); arr.insert(44); arr.insert(3); arr.insert(99); arr.insert(0); arr.insert(108); arr.insert(36); arr.display(); arr.mergeSort(); arr.display(); } }
8、递归用栈来实现
int triangle(int n)
{
if(n==1)
return 1;
else
return(n+triangle(n-1));
}
// to run this program: C>java StackTriangle2App
import java.io.*; class StackX
{
private int maxSize;
private int[] stackArray;
private int top;
public StackX(int s)
{
maxSize = s;
stackArray = new int[maxSize];
top = -1;
}
public void push(int p)
{ stackArray[++top] = p; }
public int pop()
{ return stackArray[top--]; }
public int peek()
{ return stackArray[top]; }
public boolean isEmpty()
{ return (top == -1); }
} class StackTriangle2App
{
static int theNumber;
static int theAnswer;
static StackX theStack;
public static void main(String[] args) throws IOException
{
System.out.print("Enter a number: ");
System.out.flush();
theNumber = getInt();
stackTriangle();
System.out.println("Triangle="+theAnswer);
}
public static void stackTriangle()
{
theStack = new StackX(10000);
theAnswer = 0;
while(theNumber > 0)
{
theStack.push(theNumber);
--theNumber;
}
while( !theStack.isEmpty() )
{
int newN = theStack.pop();
theAnswer += newN;
}
}
public static String getString() throws IOException
{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
public static int getInt() throws IOException
{
String s = getString();
return Integer.parseInt(s);
}
}
总结:
一个递归的方法每次用不同的参数值反复调用自身。
某种参数值使递归的方法返回,而不再调用自身。这称为基值情况。
当递归方法返回时,递归过程通过逐渐完成各层方法实例的未执行部分,而从最内层返回到最外层的原始调用处。
对于三角数字,阶乘,单词字母全排列以及二分查找,它们的递归的方法只包含一次对自身的调用。
对于汉诺塔和归并排序,它们的递归的方法包括两次递归调用。
任何可以用递归完成的操作都可以用一个栈来实现。
递归的方法可能效能低,有时可以用一个简单循环或者是一个基于栈的方法来代替它。