当我通过它推送更少的数据时,为什么我的堆栈会溢出?

时间:2017-05-18 19:14:49

标签: java recursion graphics paint

我正在制作加权美国地图,我已将邮政编码分解为3位数的邮政编码区。然后我使用for循环,循环1000次,为每个3位数的zip区域着色一个随机颜色。

每次都没有问题。如果我开始循环计数超过310,我当前的问题就出现了。任何小于310的东西都会完美地循环。因此,因为提高初始计数意味着它会减少递归代码的运行,所以这对我来说没有任何意义。

调用for循环的代码:

private void GUI()
{       
    JFrame frame = new JFrame();
    frame.setLayout(new MigLayout());

    try
    {
        mapImg = ImageIO.read(new File("Res/Zipzone map of the US.png"));
    } 
    catch (IOException e) 
    {
        e.printStackTrace();
    }
    g = mapImg.createGraphics();

    for(int i = 311; i < 1001; i++)
    {
        Random rand = new Random();
        String count = "";
        int red = rand.nextInt(220) + 25;
        int green = rand.nextInt(220) + 25;
        int blue = rand.nextInt(220) + 25;
        if(i < 100)
        {
            count = "0" + i;
        }
        else
        {
            count = i + "";
        }
        if(i <= 512)
        {
            ApplyColor(count, new Color(red, blue, green));
        }
        else if( i > 909)
        {
            ApplyColor3(count, new Color(red, blue, green));
        }
        else
        {
            ApplyColor2(count, new Color(red, blue, green));
        }
    }

    frame.add(new JLabel("", new ImageIcon(GetScaledImage(new ImageIcon(mapImg).getImage(), 1400, 875)), JLabel.CENTER), "GROW, PUSH");
    frame.setTitle("US Map");
    frame.setSize(1500,900);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}

应用颜色功能的小例子:

private void ApplyColor(String zip, Color color)
{
    int x;
    int y;
    if(zip.equals("010"))
    {
        try
        {
            x = 3339;
            y = 672;
            FloodFill(x, y, new Color(mapImg.getRGB(x, y)), color);
            x = 3361;
            y = 681;
            FloodFill(x, y, new Color(mapImg.getRGB(x, y)), color);
        }
        catch(AWTException e)
        {
            e.printStackTrace();
        }
    }
}

FloodFill功能:

public void FloodFill(int x, int y, Color targetColor, Color replacementColor) throws AWTException
{
    if(new Color(mapImg.getRGB(x, y)).equals(replacementColor))
    {
        return;
    }

    g.setColor(replacementColor);
    g.fillRect(x, y, 1, 1);

    if(new Color(mapImg.getRGB(x-1, y)).equals(targetColor))
    {
        FloodFill(x-1, y, targetColor, replacementColor);
    }

    if(new Color(mapImg.getRGB(x+1, y)).equals(targetColor))
    {
        FloodFill(x+1, y, targetColor, replacementColor);
    }

    if(new Color(mapImg.getRGB(x, y-1)).equals(targetColor))
    {
        FloodFill(x, y-1, targetColor, replacementColor);
    }

    if(new Color(mapImg.getRGB(x, y+1)).equals(targetColor))
    {
        FloodFill(x, y+1, targetColor, replacementColor);
    }
}

1 个答案:

答案 0 :(得分:2)

我真的不知道为什么从310或更高版本开始时会收到此错误,因为您的代码部分涉及您所指的内容&#34;邮政编码&#34;太过奇怪,无法尝试和理解,因为无论如何,理解这一点不会使网站的任何其他访问者受益,只有你。

我怀疑发生的事情是,从310或更高版本开始,邮政编码的安排是这样的,你需要递归填充算法来做更多的绘画,而不是你没有。

这将我们带到您的递归填充算法。

这不是进行洪水填充的正确方法。

在学术界可能被认为是正确的,但在现实世界中则不然。

如果为您的算法提供了很长的像素值,那么它将针对每一个像素进行递归。在你的初始化代码中,我看到你将帧的宽度设置为1500,而在其他地方,我看到你使用超过3000的坐标,这意味着你实际上为你的算法提供了很长的像素段来绘制。这意味着它可以大量减少。这就是你得到堆栈溢出异常的原因。

要纠正您的问题,您需要重写递归泛洪填充算法,以便它不会过多地递归。例如,每次访问左边的像素时,不要进行递归,只要有要绘制的像素,就让它循环到左边,并且只针对上面的像素和每个绘制像素下面的像素进行递归。对于访问右侧的像素也是如此。这是一种简单的方法,可以将算法的递归深度降低几个数量级。

它还具有更好的执行效果,因为一旦您知道需要连续绘制的所有像素,您可以使用单个绘图调用将它们全部绘制,而不是每个执行一个fillRect()像素。我们在这里谈论的是更好的性能。

如果这还不足以解决堆栈溢出问题,那么您可能需要考虑将算法替换为使用堆栈数据结构而不是实际调用自身的算法。将递归算法转换为使用堆栈数据结构的非递归算法,您可以查找并找到大量解决方案。