有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为什么当我推送更少的数据时堆栈会溢出?

我正在制作一张加权的美国地图,我把邮政编码分成了3位数的邮政区域。然后我使用一个for循环,循环1000次,给每个3位数的zip区域涂上随机颜色

每次都是这样,没有问题。如果我的for循环计数超过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();
        }
    }
}

以及洪水填充功能:

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) 个答案

  1. # 1 楼答案

    我真的不知道,当你从310或更多开始时,为什么会收到这个错误,因为你的代码中处理你所说的“邮政编码”的部分太奇怪了,无法尝试去理解,因为在任何情况下,理解它都不会让网站的任何其他访问者受益,只有你自己

    我怀疑的是,从310或更高的邮政编码开始,你的递归洪水填充算法需要做更多的绘画,如果你没有

    这就引出了递归洪水填充算法

    这不是填水的正确方法

    这在学术界可能被认为是正确的,但在现实世界中并非如此

    如果给了你的算法一长串的像素来绘制,它会对每一个像素进行递归。在初始化代码中,我看到您将帧的宽度设置为1500,在其他地方,我看到您使用的坐标超过3000,这意味着您实际上为算法提供了很长的像素范围来绘制。这意味着它会反复出现。这就是为什么会出现堆栈溢出异常

    要纠正您的问题,您需要重写递归洪水填充算法,这样它就不会递归太多。例如,与其每次访问左侧的像素时都进行递归,不如让它向左循环,只要有像素要绘制,并且只对每个绘制像素上方和下方的像素进行递归。访问右边的像素也是如此。这是一种将算法的递归深度减少几个数量级的简单方法

    它还有一个好处,就是性能更好,因为一旦知道了需要在一行中绘制的所有像素,就可以通过一个绘图调用来绘制它们,而不是每像素执行一次fillRect()。我们在这里讨论的是数量级的更好的性能

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