`

递归画美图,你可以做到

 
阅读更多

       在算法中有一种很好的方法叫递归,他在程序设计中应用广泛。

       递归算法解决问题的特点:

  (1) 递归就是在过程或函数里调用自身。

  (2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。

  (3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。

  (4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。

       递归算法的要求:

  递归算法所体现的“重复”一般有三个要求:

  一是每次调用在规模上都有所缩小(通常是减半);

  二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);

  三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

         以上的内容基本来自百度,我感觉递归就两个特点:自身调用自身,要有一个出口函数。

         下面进入主题,本篇博客是要说的是用递归的方法来绘制美丽的图像,真的很美丽你可以尝试一下,一共两个程序。给大家抛个砖,你可以画出更美丽的图像。

         第一个是用递归的方法画出美丽的树枝:代码如下,有注释:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
 
public class GraphicsTest extends JFrame implements ActionListener { 
    public static final double PI = Math.PI / 180; 
    JPanel panel; 
    JPanel pnlCtl; 
    JButton button; 
    JButton button2; 
    Graphics2D g2; 
 
    public GraphicsTest(String string) { 
        super(string); 
    } 
 
    public void init() { 
       
    	//面板panel用来画图,设置背景为黑色,更能体现出树的美丽
    	panel = new JPanel(); 
        panel.setBackground(Color.black);
       
        //面板panel2用来放置控制按钮
        JPanel panel2 = new JPanel(); 
        button = new JButton("美树"); 
        button2 = new JButton("清除"); 
        this.add(panel, BorderLayout.CENTER); 
        button.addActionListener(this); 
        button2.addActionListener(this); 
        panel2.setBackground(Color.green);
        panel2.add(button); 
        panel2.add(button2); 
        this.add(panel2, BorderLayout.NORTH); 
        setSize(800, 600); 
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        this.setVisible(true); 
        Dimension winSize = Toolkit.getDefaultToolkit().getScreenSize(); 
        this.setLocation((winSize.width - this.getWidth()) / 2, 
                (winSize.height - this.getHeight()) / 2); 
        g2 = (Graphics2D) panel.getGraphics(); 
    } 
 
    public static void main(String[] args) throws ClassNotFoundException, 
        InstantiationException, IllegalAccessException, 
        UnsupportedLookAndFeelException { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
        GraphicsTest testPanel = new GraphicsTest("美丽的分形"); 
        testPanel.init(); 
    } 
 
     
    @Override 
    public void actionPerformed(ActionEvent e) { 
        if ("美树".equals(e.getActionCommand())) { 
            drawLeaf(g2, 400, 500, 100, 210+random.nextInt(100)); 
        } else if ("清除".equals(e.getActionCommand())) { 
        	panel.getGraphics().setColor(Color.black);
        	panel.getGraphics().fillRect(0, 0, 800, 800);
        } 
    } 
    Random random=new Random(); 
    public void  drawLeaf(Graphics g, double x, double y, double L, double a) { 
       
        int red = random.nextInt(127); 
        int green = random.nextInt(127); 
        int blue = random.nextInt(127); 
        //随机颜色 
        g.setColor(new Color(red, green, blue)); 
        double x1, x2, x1L, x2L, x2R, x1R, y1, y2, y1L, y2L, y2R, y1R; 
       
        //侧干主干的夹角 
        float deflection = 50-random.nextInt(20);
        //主干偏转角度 
        float intersection = random.nextInt(40)-20; 
        //限制递归深度 
        float depth = 2+random.nextInt(2);
        //主干侧干长度比(可调整使其更茂密或稀疏) 
        float ratio = 3f;
        
        //上级主干与本级主干长度比(可调整使其变高低) 
        float ratio2 = 1.2f;
        if (L > depth) { 
            x2=x+L*Math.cos(a*PI); 
            y2=y+L*Math.sin(a*PI); 
            x2R=x2+L/ratio*Math.cos((a+deflection)*PI); 
            y2R=y2+L/ratio*Math.sin((a+deflection)*PI); 
            x2L=x2+L/ratio*Math.cos((a-deflection)*PI); 
            y2L=y2+L/ratio*Math.sin((a-deflection)*PI); 
            x1=x+L/ratio*Math.cos(a*PI); 
            y1=y+L/ratio*Math.sin(a*PI); 
            x1L=x1+L/ratio*Math.cos((a-deflection)*PI); 
            y1L=y1+L/ratio*Math.sin((a-deflection)*PI); 
            x1R=x1+L/ratio*Math.cos((a+deflection)*PI); 
            y1R=y1+L/ratio*Math.sin((a+deflection)*PI); 
            g.drawLine((int)x,(int)y,(int)x2,(int)y2); 
            g.drawLine((int)x2,(int)y2,(int)x2R,(int)y2R); 
            g.drawLine((int)x2,(int)y2,(int)x2L,(int)y2L); 
            g.drawLine((int)x1,(int)y1,(int)x1L,(int)y1L);   
            g.drawLine((int)x1,(int)y1,(int)x1R,(int)y1R); 
           
            //递归调用
            drawLeaf(g,x2,y2,L/ratio2,a+intersection); 
            drawLeaf(g,x2R,y2R,L/ratio,a+deflection); 
            drawLeaf(g,x2L,y2L,L/ratio,a-deflection); 
            drawLeaf(g,x1L,y1L,L/ratio,a-deflection); 
            drawLeaf(g,x1R,y1R,L/ratio,a+deflection); 
        } 
    } 
} 

   运行如下:

 

 多画几支,你会发现他很像孔雀开的屏:



 是不是很漂亮,你可以改改代码做出更美丽的图。

 

 

 

 

下面是也是应用递归画出的一个,这个叫做“神奇的色子”具体的要求如下:

1.平面上随机选A,B,C三个点。再随机选一个点,记为P。
2.有一个三面色子,每丢一次,则选中ABC三个中一点。
开始游戏:
1.重复丢色子,如果选中A,则取A和P的中点P1,画黑,
2.如果选中B,则取B和P1的中点P2,画黑
3.如果选中A,则取A和P2的中点P3,画黑
4….一直重复(如每点一下鼠标,丢100次色子。)

当你按要求继续下去的时候你会发现出现很神奇的一幕不多说代码如下:(有注释)

package 神奇的色子;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Drawsezi extends JFrame implements ActionListener{
	
	//入口函数
	public static void main(String[] args) {
		Drawsezi se = new Drawsezi();
		se.init();
	}
	
	//设置画图板
	public void init() {
		
		//初始化画板
		this.setSize(600, 600);
		this.setDefaultCloseOperation(3);
		this.setLayout(new FlowLayout());
		this.setLocationRelativeTo(null);
		this.getContentPane().setBackground(Color.black);
		this.setVisible(true);
		
		//获取画布对象
		 g =this.getGraphics();
		
		 //添加一个控制按钮
		JButton bu = new JButton("画图");
		//bu.setActionCommand("draw");
		this.add(bu);
		bu.addActionListener(this);
	}
	
	//产生四个点的随机数10--999,防止点在画布外面
	Random r = new Random();
    int Ax = r.nextInt(700)+10;
    int Ay = r.nextInt(700)+10;
    int Bx = r.nextInt(700)+10;
    int By = r.nextInt(700)+10;
    int Cx = r.nextInt(700)+10;
    int Cy = r.nextInt(700)+10;
    int Dx = r.nextInt(700)+10;
    int Dy = r.nextInt(700)+10;
    int Ex = r.nextInt(700)+10;
    int Ey = r.nextInt(700)+10;
    int Px = r.nextInt(700)+10;
    int Py = r.nextInt(700)+10;
    
	
	//重写ActionListener的方法
    public void actionPerformed(ActionEvent e) {
      
        for(int i = 0; i < 10000; i++) {    
            int m = r.nextInt(5);     //产生随机数0,1,2,4对应A,B,C,D
          if(m == 0) {                //选中A
        	  Px = (Ax+Px)/2;
        	  Py = (Ay+Py)/2;
        	  g.setColor(new Color(50,230,0));
        	  g.drawLine(Px, Py, Px, Py);
        	  
          } else if(m == 1) {          //选中B
        	  Px = (Bx+Px)/2;
        	  Py = (By+Py)/2;
        	  g.setColor(new Color(225,0,30));
        	  g.drawLine(Px, Py, Px, Py);
        	  
         
          }else if(m == 2) {           //选中C
        	  Px = (Cx+Px)/2;
        	  Py = (Cy+Py)/2;
        	  g.setColor(new Color(0,35,123));
        	  g.drawLine(Px, Py, Px, Py);
        	  
          }
        }
       
    }
    
    //将g设置为全局变量
    private Graphics g;
    
}

  运行结果:



 

 仔细观察你会发现上面的每个图像的规律,这像上面的那一颗树枝,看上去没有什么规律,其实他的每一个小树枝都和大的树枝一模一样,不信你仔细看,这就是递归的神奇之处,把一个大的东西分成一个一个小的东西,这就是分形的精髓,我们也从中可以看出世间万物的规律,大的事务都是由小的事物组成,只要你有一双慧眼,你就会看出他们的规律。这种感觉真的很好。

 

  • 大小: 75.3 KB
  • 大小: 199.6 KB
  • 大小: 51.7 KB
  • 大小: 42.4 KB
2
1
分享到:
评论
2 楼 rex0654335 2013-12-30  
楼主不更新了?
1 楼 kidneyball 2013-11-26  
这种画有个学名叫“分形图”,你感兴趣的话可以找个Apophysis来把玩一下,或者去“分形艺术网”看看。

相关推荐

    递归画树(Qt实现)

    接下来,我们可以通过递归方式遍历二叉树并绘制每个节点。递归函数的基本思想是从根节点开始,然后分别对左右子树进行相同的操作。在Qt中,我们可以创建一个方法,接收当前节点和其在画布上的位置作为参数,如下所示...

    java 递归 画树

    画树的过程可以抽象为一个递归函数,接受当前节点的信息作为参数。函数会先在界面上绘制当前节点,然后对每个子节点进行相同的操作,直到遇到叶子节点。在Java中,我们可以使用Swing库来创建GUI元素,如JPanel,然后...

    递归分形树之动画实现

    总的来说,递归分形树的动画实现是一个融合了数学、算法和艺术的项目,它可以锻炼你的编程技能,同时也是一种探索数学美学和自然界规律的好方式。通过不断迭代和优化,你可以创造出更加逼真和复杂的分形树动画。

    C#递归算法画树C#递归算法画树C#递归算法画树

    在C#编程中,递归是一种强大的工具,它允许函数调用自身来解决...通过实践和理解递归的原理,你可以创建出更加多样化和复杂的树形图形,不仅限于控制台输出,还可以应用于各种图形用户界面或网络应用的可视化设计中。

    C语言写的汉诺塔递归单步的图形展示动画

    这个过程可以形象地用动画来展示,使得用户能够直观地理解递归的过程。"C语言写的汉诺塔递归单步的图形展示动画"就是这样一个程序,它使用C语言编程实现,通过图形化界面动态演示汉诺塔的移动过程。 C语言是一种...

    opengl画球,递归细分

    在画球的过程中,我们可以设定一个递归深度,每次递归都会将当前的三角形分割为四个更小的三角形,直到达到预设的最小尺寸或者达到最大递归深度。 以下是实现递归画球的基本步骤: 1. **初始化**: 在OpenGL上下文...

    e语言-易语言递归算法画树

    在画树的过程中,递归可以非常直观地模拟自然界中树的分枝结构。每棵树都可以看作是由一个根节点和若干子树构成,而每个子树又可以进一步分解为更小的子树,这就是递归的基本思想。 首先,我们需要理解递归函数的...

    递归树, 真的是画一棵树.

    在描述中提到的“用VB画植物”,实际上可能是通过递归算法来模拟植物生长的过程,比如生成树的形态。植物生长的自然规律往往具有递归特性,例如树枝从主干生长出,又会产生更小的枝丫,这种结构可以用递归来抽象和...

    C# 递归绘制数学图形

    在C#编程语言中,递归是一种强大的编程技术,它涉及到函数或方法调用自身来解决问题。...它不仅可以帮助你掌握递归的概念,还可以激发你对编程艺术的兴趣。通过不断的试验和改进,你可以创造出令人惊叹的数字艺术作品。

    易语言递归算法画树

    通过阅读和分析这段代码,你可以更深入地理解递归算法在绘制树形结构中的应用,以及易语言如何处理图形绘制和递归调用。如果你正在学习易语言或递归算法,这是一个很好的实践案例,可以帮助你提升编程技能。 总结来...

    C#递归 C#递归 C#递归

    递归通常用于解决可以通过重复相同过程分解成更小问题的问题。递归方法包含两个主要部分: 1. **基本情况**(Base Case):这是递归结束的条件。 2. **递归步骤**(Recursive Step):这是一系列操作,其中最后一步...

    方格递归代码

    这个函数的任务是在画布上画出当前正方形,并对每个子区域进行递归调用,除非其边长小于或等于最小值。 3. **绘制当前正方形**:在画布上用适当的颜色或标记填充当前正方形的区域。 4. **判断递归条件**:检查当前...

    图形化编程 scratch 递归 二叉树(带叶子).sb3

    通过自制积木实现递归画出一颗树,每次画的效果都不一样。

    .net 递归算法 .net 递归算法.net 递归算法

    递归的核心思想是将大问题分解为相同或相似的小问题,直到问题变得足够简单,可以直接得出答案。这种解决问题的方式在数据结构、算法设计以及某些特定场景的计算中非常常见。 递归算法的基本要素包括: 1. **基础...

    可并行递归算法的递归多线程实现

    为此,我们可以在每个递归调用中创建新的线程,这些线程可以独立运行直到它们各自完成,从而实现真正的并行处理。 #### 结论 递归多线程算法的实现,特别是使用Java这样的现代编程语言,为并行计算提供了一个强大...

    阿克曼函数 c程序 递归与非递归算法的综合

    通过比较这两个程序,你可以看到递归和非递归算法在实现上的差异,以及它们在处理复杂递归问题时的不同策略。 理解并分析这两个程序,可以帮助你深入学习C语言编程,特别是递归和栈的概念。同时,这也为理解递归...

    递归算法ppt让你快速上手

    "递归算法ppt让你快速上手" 递归算法是计算机科学中的一种重要算法思想,它可以解决许多复杂的问题。下面是递归算法的知识点总结: 1. 递归的定义:若一个对象部分地包含它自己,或用它自己给自己定义,则称这个...

    递归算法与非递归转化

    递归算法和非递归算法可以相互转换。将递归算法转换为非递归算法有两种方法,一种是直接求值,不需要回溯;另一种是不能直接求值,需要回溯。前者使用一些变量保存中间结果,称为直接转换法;后者使用栈保存中间结果...

    用matlab工具箱计算并画出递归结构图(Recurrence_plots)的代码

    首先,递归结构图是一种二维图形,它通过在时间序列的自我相似部分中画点来展示序列的结构和动态行为。这种方法由Eckmann等人于1987年提出,它能够直观地揭示出序列的周期性、混沌、分岔等复杂特性,而无需对原始...

Global site tag (gtag.js) - Google Analytics