递归中的堆栈溢出
我正在制作一种 MS Paint 应用程序,它绘制轮廓并填充内部。我编写了填充轮廓的递归函数。它工作正常,但如果conture太大,程序会抛出stackoverflow异常。我该如何解决这个问题?我什至无法捕捉到这个异常((
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport( "user32.dll" )]
static extern IntPtr GetDC( IntPtr hWnd );
[DllImport( "user32.dll" )]
static extern int ReleaseDC( IntPtr hWnd, IntPtr hDC );
[DllImport( "gdi32.dll" )]
static extern int GetPixel( IntPtr hDC, int x, int y );
[DllImport( "gdi32.dll" )]
static extern int SetPixel( IntPtr hDC, int x, int y, int color );
static public Color GetPixel( Control control, int x, int y )
{
Color color = Color.Empty;
if (control != null)
{
IntPtr hDC = GetDC( control.Handle );
int colorRef = GetPixel( hDC, x, y );
color = Color.FromArgb(
(int)(colorRef & 0x000000FF),
(int)(colorRef & 0x0000FF00) >> 8,
(int)(colorRef & 0x00FF0000) >> 16 );
ReleaseDC( control.Handle, hDC );
}
return color;
}
static public void SetPixel( Control control, int x, int y, Color color )
{
if (control != null)
{
IntPtr hDC = GetDC( control.Handle );
int argb = color.ToArgb();
int colorRef =
(int)((argb & 0x00FF0000) >> 16) |
(int)(argb & 0x0000FF00) |
(int)((argb & 0x000000FF) << 16);
SetPixel( hDC, x, y, colorRef );
ReleaseDC( control.Handle, hDC );
}
}
int oldX, oldY;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Graphics g = panel1.CreateGraphics();
g.Clear(panel1.BackColor);
}
bool paint;
private void Form1_Load(object sender, EventArgs e)
{
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
oldX = e.X;
oldY = e.Y;
paint = true;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
paint = false;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (paint)
{
Graphics g = panel1.CreateGraphics();
Pen p = new Pen(Color.Black);
g.DrawLine(p, oldX, oldY, e.X, e.Y);
oldX = e.X;
oldY = e.Y;
}
}
private void panel1_MouseDoubleClick(object sender, MouseEventArgs e)
{
fill(e.X, e.Y, Color.Black, Color.Red);
Color c = GetPixel(panel1, e.X, e.Y);
ClearButton.BackColor = c;
label1.Text = e.X + " " + e.Y;
}
private void fill(int x, int y, Color border, Color c) {
Color PointedColor = GetPixel(panel1, x, y);
try {
if (PointedColor.R != border.R && PointedColor.G != border.G && PointedColor.B != border.B &&
PointedColor.R != c.R && PointedColor.G != c.G && PointedColor.B != c.B &&
x >= 0 && x < panel1.Size.Width && y >= 0 && y < panel1.Size.Height)
{
SetPixel(panel1, x, y, c);
fill(x - 1, y, border, c);
fill(x + 1, y, border, c);
fill(x, y - 1, border, c);
fill(x, y + 1, border, c);
}
}
catch(System.StackOverflowException e)
{
label1.Text = e.Message;
}
}
}
}
i'm making kinda ms paint application, that draws conture and fill inside.I wrote recursive function that fills conture. It works fine ,but if conture is too big program throws stackoverflow exception. How can i solve this problem?? i even can't catch this exception((
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport( "user32.dll" )]
static extern IntPtr GetDC( IntPtr hWnd );
[DllImport( "user32.dll" )]
static extern int ReleaseDC( IntPtr hWnd, IntPtr hDC );
[DllImport( "gdi32.dll" )]
static extern int GetPixel( IntPtr hDC, int x, int y );
[DllImport( "gdi32.dll" )]
static extern int SetPixel( IntPtr hDC, int x, int y, int color );
static public Color GetPixel( Control control, int x, int y )
{
Color color = Color.Empty;
if (control != null)
{
IntPtr hDC = GetDC( control.Handle );
int colorRef = GetPixel( hDC, x, y );
color = Color.FromArgb(
(int)(colorRef & 0x000000FF),
(int)(colorRef & 0x0000FF00) >> 8,
(int)(colorRef & 0x00FF0000) >> 16 );
ReleaseDC( control.Handle, hDC );
}
return color;
}
static public void SetPixel( Control control, int x, int y, Color color )
{
if (control != null)
{
IntPtr hDC = GetDC( control.Handle );
int argb = color.ToArgb();
int colorRef =
(int)((argb & 0x00FF0000) >> 16) |
(int)(argb & 0x0000FF00) |
(int)((argb & 0x000000FF) << 16);
SetPixel( hDC, x, y, colorRef );
ReleaseDC( control.Handle, hDC );
}
}
int oldX, oldY;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Graphics g = panel1.CreateGraphics();
g.Clear(panel1.BackColor);
}
bool paint;
private void Form1_Load(object sender, EventArgs e)
{
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
oldX = e.X;
oldY = e.Y;
paint = true;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
paint = false;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (paint)
{
Graphics g = panel1.CreateGraphics();
Pen p = new Pen(Color.Black);
g.DrawLine(p, oldX, oldY, e.X, e.Y);
oldX = e.X;
oldY = e.Y;
}
}
private void panel1_MouseDoubleClick(object sender, MouseEventArgs e)
{
fill(e.X, e.Y, Color.Black, Color.Red);
Color c = GetPixel(panel1, e.X, e.Y);
ClearButton.BackColor = c;
label1.Text = e.X + " " + e.Y;
}
private void fill(int x, int y, Color border, Color c) {
Color PointedColor = GetPixel(panel1, x, y);
try {
if (PointedColor.R != border.R && PointedColor.G != border.G && PointedColor.B != border.B &&
PointedColor.R != c.R && PointedColor.G != c.G && PointedColor.B != c.B &&
x >= 0 && x < panel1.Size.Width && y >= 0 && y < panel1.Size.Height)
{
SetPixel(panel1, x, y, c);
fill(x - 1, y, border, c);
fill(x + 1, y, border, c);
fill(x, y - 1, border, c);
fill(x, y + 1, border, c);
}
}
catch(System.StackOverflowException e)
{
label1.Text = e.Message;
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您应该使用非递归洪水填充算法。
有关说明,请参阅维基百科文章
Bob Powell 有一些源代码这里。
请注意,尝试通过每次创建新线程来解决当前堆栈溢出的问题是一个非常昂贵的解决方案:采用简单的非递归解决方案绝对是更好的方法。创建额外的线程来解决堆栈问题并不是线程的正确使用方式。如果您认为通过使用多个线程可以获得更好的性能,即使这样您也应该采用非递归解决方案。
You should use a non-recursive flood fill algorithm.
For a description see the wikipedia article
Bob Powell has some source code here.
Note that attempting to solve the issue of the current stack overflowing by creating a new thread every time is a very expensive solution: going with a simple non-recursive solution is definitely the better approach. Creating additional threads to overcome the stack issue is not the right use of threads. If you thought you could get better performance by using multiple threads, even then you should go with a non-recursive solution.
您不能捕获
StackOverflowException
按设计:我确信有更有效的方法可以实现这一目标。但是,首先,您可以通过将调用堆栈具体化为
Stack
将递归转换为迭代:You are not allowed to catch a
StackOverflowException
by design:I’m sure there are more efficient ways of achieving this. However, to start you off, you can convert your recursion to an iteration by reifying the call stack as a
Stack<T>
: