递归调用蒙德里安生成器时参数归零导致无限循环问题
解决蒙德里安生成器的无限递归与参数异常问题
核心问题分析
你的代码存在几个致命逻辑错误,直接导致了无限运行和参数归零的问题:
- 整数转换错误:
(int) size会把nextDouble()返回的0~1小数直接截断为0,使得w * (int) size和h * (int) size全部变成0,递归传入的尺寸直接失效。 - 循环与递归冲突:递归函数里使用
while循环完全冗余,递归本身就是处理重复细分的逻辑,while会导致同一层级代码反复执行,陷入死循环。 - 绘制参数逻辑混乱:
fillRect(tx, ty, tx-w, ty-h)的宽高参数为负数,且完全不符合当前子矩形的绘制范围。 - 冗余操作:每次调用
subdivide都填充整个白色画布,会覆盖之前所有绘制;重复创建Random对象,浪费资源。
修正后的完整代码
import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.util.Random; public class Mondrian extends JPanel { private static final int CUTOFF = 40; private static final Color[] COLORS = {Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK}; private Random rng = new Random(); private Image mondrian; public Mondrian(int w, int h) { mondrian = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = (Graphics2D) mondrian.getGraphics(); // 仅初始化一次白色背景,避免覆盖已有绘制 g2.setColor(Color.WHITE); g2.fillRect(0, 0, w, h); // 初始调用细分方法,传入正确的初始尺寸 subdivide(0, 0, w, h, g2); } private void subdivide(int tx, int ty, int w, int h, Graphics2D g2) { // 尺寸小于阈值时,绘制边框后终止递归 if (w <= CUTOFF && h <= CUTOFF) { g2.setColor(Color.BLACK); g2.drawRect(tx, ty, w, h); return; } // 60%概率分割矩形,40%概率填充颜色 double splitChance = rng.nextDouble(); if (splitChance < 0.6) { int splitPos; if (w > h) { // 横向分割,确保分割后两部分都不小于阈值 splitPos = rng.nextInt(w - 2 * CUTOFF) + CUTOFF; subdivide(tx, ty, splitPos, h, g2); subdivide(tx + splitPos, ty, w - splitPos, h, g2); // 绘制分割线 g2.setColor(Color.BLACK); g2.drawLine(tx + splitPos, ty, tx + splitPos, ty + h); } else { // 纵向分割,确保分割后两部分都不小于阈值 splitPos = rng.nextInt(h - 2 * CUTOFF) + CUTOFF; subdivide(tx, ty, w, splitPos, g2); subdivide(tx, ty + splitPos, w, h - splitPos, g2); // 绘制分割线 g2.setColor(Color.BLACK); g2.drawLine(tx, ty + splitPos, tx + w, ty + splitPos); } } else { // 随机选择颜色填充当前矩形 Color color = COLORS[rng.nextInt(COLORS.length)]; g2.setColor(color); g2.fillRect(tx, ty, w, h); // 绘制矩形边框 g2.setColor(Color.BLACK); g2.drawRect(tx, ty, w, h); } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 将生成的图像绘制到面板上 g.drawImage(mondrian, 0, 0, getWidth(), getHeight(), this); } public static void main(String[] args){ SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Mondrian Generator"); Mondrian mondrian = new Mondrian(800, 1000); frame.add(mondrian); frame.setSize(800, 1000); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); } }
关键修改说明
- 修复尺寸计算逻辑:通过
rng.nextInt(w - 2 * CUTOFF) + CUTOFF生成分割位置,确保分割后的子矩形尺寸不小于阈值,彻底避免尺寸归零。 - 递归逻辑优化:用
if判断替代while循环,符合递归的终止条件设计,避免死循环。 - 修正绘制参数:所有
fillRect和drawRect都使用当前子矩形的起始坐标与尺寸,确保绘制区域正确。 - 补充必要实现:添加
paintComponent方法,确保生成的图像能显示在面板上;使用SwingUtilities.invokeLater保证Swing组件线程安全。 - 优化资源使用:复用类内的
Random对象,仅初始化一次白色背景。
内容的提问来源于stack exchange,提问作者Snowbird2001
相关产品推荐
相关产品推荐

