Java中的递归
1.何为递归,递归与循环有何区别?
程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
看了递归的定义,可能大家对递归有了大致的认识,但是也可能有人会觉得,那这样的话,递归何循环有什么区别呢,我不是只需要用循环就可以解决递归的问题了吗。
事实上并不是这样,接下来我们来看看递归和循环的区别:
递归与循环是两种不同的解决问题的典型思路。
递归算法:
优点:代码简洁、清晰,并且容易验证正确性。(如果你真的理解了算法的话,否则你更晕)
缺点:它的运行需要较多次数的函数调用,如果调用层数比较深,需要增加额外的堆栈处理,比如参数传递需要压栈等操作,会对执行效率有一定影响。但是,对于某些问题,如果不使用递归,那将是极端难看的代码。
循环算法:
优点:速度快,结构简单。
缺点:并不能解决所有的问题。有的问题适合使用递归而不是循环。如果使用循环并不困难的话,最好使用循环。
递归算法 和循环算法总结
-
一般递归调用可以处理的算法,也通过循环去解决常需要额外的低效处理 。
-
现在的编译器在优化后,对于多次调用的函数处理会有非常好的效率优化,效率未必低于循环。
2.递归算法的运用
其实递归联系到数学中去就类似于数学归纳法。
例:
当n=1时等式成立
假设n=k时等式成立
此时n=k+1也成立
所以等式都成立。
接下来我们试着用递归和循环来求一下著名的数学问题斐波那契数列
斐波那契数列:斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368…
这个数列从第3项开始,每一项都等于前两项之和。
因此可写出其表达式an=an-1+an-2;
import java.util.Scanner;
public class Fibonacci {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please input this fibonacci n:");
int n = scanner.nextInt(); // 假设输入为大于零的整数
System.out.println(fibonacci(n) + ":" + fibonacciNormal(n));
int sum = 0;
for(int i = 1; i <= n; i++){
sum += fibonacci(i);
}
System.out.println(sum);
}
// 递归实现方式
public static int fibonacci(int n){
if(n <= 2){
return 1;
}else{
return fibonacci(n-1) + fibonacci(n-2);
}
}
// 递推实现方式
public static int fibonacciNormal(int n){
if(n <= 2){
return 1;
}
int n1 = 1, n2 = 1, sn = 0;
for(int i = 0; i < n - 2; i ++){
sn = n1 + n2;
n1 = n2;
n2 = sn;
}
return sn;
}
}
我们可以很显然地看出递归和循环的区别。
其实递归不仅仅可以原来解决数学问题,实际上很多生活中的美丽图形都是通过递归形成的。
3.生活中的递归之美
刚刚的斐波那契数列在生活中表现出来就是如此
除此之外,还有许多美丽的图形是根据递归形成的如Sierpinski三角形:
还有门格海绵
接下来我们就试着用画图板来画出这些图形
建立画图板
import java.awt.Graphics;
import javax.swing.JFrame;
public class DrawUI {
int x[] = new int[7];
int y[] = new int[7];
public void showUI() {
JFrame loginFrame = new JFrame();
loginFrame.setSize(1000, 1000);
loginFrame.setLocationRelativeTo(null);
loginFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// 创建监听器对象
Listener2 click = new Listener2();
// 给窗体添加鼠标监听器
loginFrame.addMouseListener(click);
// 设置窗体可见
loginFrame.setVisible(true);
// 获取窗体的画布
Graphics g = loginFrame.getGraphics();
// 给监听器的画布属性赋值
click.g = g;
// 主方法
public static void main(String[] args) {
// 创建界面的对象
DrawUI dp = new DrawUI();
// 显示界面
dp.showUI();
}
}
接下来画Sierpinski三角形:
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Listener implements MouseListener {
int x[] = new int[3], y[] = new int[3], i = 0;
Graphics g;
void Sierpinski(int x1, int y1, int x2, int y2, int x3, int y3, int a) {
if (a == 0) {
g.drawLine(x1, y1, x2, y2);
g.drawLine(x2, y2, x3, y3);
g.drawLine(x3, y3, x1, y1);
} else {
Sierpinski(x1, y1, (x1 + x2) / 2, (y1 + y2) / 2, (x1 + x3) / 2,
(y1 + y3) / 2, a - 1);
Sierpinski((x1 + x2) / 2, (y1 + y2) / 2, x2, y2, (x2 + x3) / 2,
(y2 + y3) / 2, a - 1);
Sierpinski((x1 + x3) / 2, (y1 + y3) / 2, (x2 + x3) / 2,
(y2 + y3) / 2, x3, y3, a - 1);
g.drawLine(x1, y1, x2, y2);
g.drawLine(x2, y2, x3, y3);
g.drawLine(x3, y3, x1, y1);
}
}
public void mousePressed(MouseEvent e) {
// 获取坐标
x[i] = e.getX();
y[i] = e.getY();
g.drawOval(x[i], y[i], 3, 3);
System.out.println("(" + x[i] + "," + y[i] + ")");
i = i + 1;
}
public void mouseReleased(MouseEvent e) {
if (i == 3) {
Sierpinski(x[0], y[0], x[1], y[1], x[2], y[2], 5);
i = 0;
}
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
效果如图
如果要画门格地毯
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Listener2 implements
MouseListener {
int x1, y1, x2, y2, x, y;
Graphics g;
void ditang(int x1, int y1, int length, int a) {
g.drawRect(x1,y1, length, length);
if(a == 0) {
}else {
ditang(x1,y1, length / 3, a - 1);
ditang(x1+length / 3, y1, length / 3, a - 1);
ditang(x1,y1 + length / 3, length / 3, a - 1);
ditang(x1 + 2 * length / 3, y1,length / 3, a - 1);
ditang(x1,y1 + 2 * length / 3, length / 3, a - 1);
ditang(x1+ 2 * length / 3, y1 + 2 * length / 3, length / 3, a - 1);
ditang(x1+ 2 * length / 3, y1 + length / 3, length / 3, a - 1);
ditang(x1+ length / 3, y1 + 2 * length / 3, length / 3, a - 1);
}
}
public void mousePressed(MouseEvent e) {
//获取坐标
x1= e.getX();
y1= e.getY();
System.out.println("("+ x1 + "," + y1 + ")");
}
public void mouseReleased(MouseEvent e) {
x2= e.getX();
y2= e.getY();
if(x1 <= x2 && y1 <= y2) {
x= x1;
y= y1;
}else if (x1 <= x2 && y2 <= y1) {
x= x1;
y= y2;
}else if (x2 <= x1 && y2 <= y1) {
x= x2;
y= y2;
}else if (x2 <= x1 && y1 <= y2) {
x= x2;
y= y1;
}
ditang(x,y, Math.abs(x1 - x2), 5);
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
效果如图