Java 当我推送更少的数据通过堆栈时,为什么堆栈会溢出?
我正在制作一张加权的美国地图,我把邮政编码分成了3位数的邮政区域。然后,我使用一个for循环,该循环迭代1000次,将每个3位数的zip区域涂成随机颜色 每次都是这样,没有问题。如果我开始for循环计数超过310,我当前的问题就出现了。只要小于310,它就会完美地循环通过。因此,由于提高初始计数意味着它将更少地运行递归代码,因此这对我来说是有意义的 调用for循环的代码:Java 当我推送更少的数据通过堆栈时,为什么堆栈会溢出?,java,recursion,graphics,paint,Java,Recursion,Graphics,Paint,我正在制作一张加权的美国地图,我把邮政编码分成了3位数的邮政区域。然后,我使用一个for循环,该循环迭代1000次,将每个3位数的zip区域涂成随机颜色 每次都是这样,没有问题。如果我开始for循环计数超过310,我当前的问题就出现了。只要小于310,它就会完美地循环通过。因此,由于提高初始计数意味着它将更少地运行递归代码,因此这对我来说是有意义的 调用for循环的代码: private void GUI() { JFrame frame = new JFrame();
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);
}
}
我真的不知道当你从310或更多开始时为什么会收到这个错误,因为你的代码中处理你所说的“邮政编码”的部分太离奇了,无法尝试去理解,因为在任何情况下,理解它都不会让网站的任何其他访问者受益,只有你自己 我怀疑的是,从310或以上开始,邮政编码的排列方式使得递归泛洪填充算法需要进行更多的绘制 这就引出了递归洪水填充算法 那不是填水的正确方法 这在学术界可能被认为是正确的,但在现实世界中则不然 如果给你的算法一长串的像素来绘制,它将对每一个像素递归。在初始化代码中,我看到您将帧的宽度设置为1500,在其他地方,我看到您使用的坐标超过3000,这意味着您实际上为算法提供了很长的像素长度来绘制。这意味着它经常重复出现。这就是为什么会出现堆栈溢出异常 要纠正您的问题,您需要重写递归泛洪填充算法,以便它不会递归太多。例如,与每次访问左侧的像素时递归不同,只要有要绘制的像素,就让它向左循环,并且只对每个绘制像素上方和下方的像素递归。访问右侧的像素也是如此。这是一种将算法的递归深度减少几个数量级的简单方法 它还具有性能更好的优点,因为一旦知道了需要在一行中绘制的所有像素,就可以通过一个绘图调用来绘制它们,而不是每像素执行一次
fillRect()
。我们在这里谈论的是数量级的更好的性能
如果这还不足以解决堆栈溢出问题,那么您可能需要考虑用一个堆栈数据结构替换您的算法,而不是实际调用自己。将递归算法转换为使用堆栈数据结构的非递归算法是您可以查找并找到大量解决方案的事情。
我真的不知道当您从310或更多开始时为什么会收到此错误,因为代码中处理您所指的“邮政编码”的部分这太离奇了,无法理解,因为在任何情况下,理解这一点都不会让网站的任何其他访问者受益,只有你 我怀疑的是,从310或以上开始,邮政编码的排列方式使得递归泛洪填充算法需要进行更多的绘制 这就引出了递归洪水填充算法 那不是填水的正确方法 这在学术界可能被认为是正确的,但在现实世界中则不然 如果给你的算法一长串的像素来绘制,它将对每一个像素递归。在初始化代码中,我看到您将帧的宽度设置为1500,在其他地方,我看到您使用的坐标超过3000,这意味着您实际上为算法提供了很长的像素长度来绘制。这意味着它经常重复出现。这就是为什么会出现堆栈溢出异常 要纠正您的问题,您需要重写递归泛洪填充算法,以便它不会递归太多。例如,与每次访问左侧的像素时递归不同,只要有要绘制的像素,就让它向左循环,并且只对每个绘制像素上方和下方的像素递归。访问右侧的像素也是如此。这是一种将算法的递归深度减少几个数量级的简单方法 它还具有性能更好的优点,因为一旦知道了需要在一行中绘制的所有像素,就可以通过一个绘图调用来绘制它们,而不是每像素执行一次fillRect()
。我们在这里谈论的是数量级的更好的性能
如果这还不足以解决堆栈溢出问题,那么您可能需要考虑用一个堆栈数据结构替换您的算法,而不是实际调用自己。将递归算法转换为使用堆栈数据结构的非递归算法是您可以查找并找到大量解决方案的事情。
哦,还有一件事:我没有看到您在任何地方执行任何检查,以查看您的x或y是否超过图像的尺寸。我希望您有一些技巧来处理这个问题,即在图像边缘周围绘制一个边框,它永远不会等于targetColor
。感谢您提供的非常详细的建议。我对洪水填充做了更多的研究,并提出了一个更适合我的排队系统。哦,还有一件事:我没有看到你在任何地方进行任何检查,看你的x或y是否超过了图像的尺寸。我希望你有一些技巧来处理这个问题,即在你的图像边缘画一个边界,它永远不会等于