Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 不同的填海方法_C#_Recursion_Queue_Stack Overflow_Flood Fill - Fatal编程技术网

C# 不同的填海方法

C# 不同的填海方法,c#,recursion,queue,stack-overflow,flood-fill,C#,Recursion,Queue,Stack Overflow,Flood Fill,好的,各位,我有几种不同的方法来进行注水。所有这些都会引起问题。我将列出这3种方法,并解释每种方法会发生什么。如果有人能给我一些建议那就太好了。我看过一些类似的帖子,但没有一篇是针对C#、java或VB.net(我所知道的唯一语言)的 我有一个名为PixelData的类,它将颜色存储在CellColor成员变量中。我有一个称为“像素”的像素数据对象数组,大小为50x50。我还有一个常量CANVAS_SIZE,在本例中为50。以下是我尝试过的三种方法 这个是递归的。它极易发生堆栈溢出。我尝试设置一

好的,各位,我有几种不同的方法来进行注水。所有这些都会引起问题。我将列出这3种方法,并解释每种方法会发生什么。如果有人能给我一些建议那就太好了。我看过一些类似的帖子,但没有一篇是针对C#、java或VB.net(我所知道的唯一语言)的

我有一个名为PixelData的类,它将颜色存储在CellColor成员变量中。我有一个称为“像素”的像素数据对象数组,大小为50x50。我还有一个常量CANVAS_SIZE,在本例中为50。以下是我尝试过的三种方法

这个是递归的。它极易发生堆栈溢出。我尝试设置一个计时器,在该方法完成后启用CanFill成员。这仍然不能防止溢出:

private void FloodFill(Point node, Color targetColor, Color replaceColor)
{
  //perform bounds checking X
  if ((node.X >= CANVAS_SIZE) || (node.X < 0))
    return; //outside of bounds

  //perform bounds checking Y
  if ((node.Y >= CANVAS_SIZE) || (node.Y < 0))
    return; //ouside of bounds

  //check to see if the node is the target color
  if (pixels[node.X, node.Y].CellColor != targetColor)
    return; //return and do nothing
  else
  {
    pixels[node.X, node.Y].CellColor = replaceColor;

    //recurse
    //try to fill one step to the right
    FloodFill(new Point(node.X + 1, node.Y), targetColor, replaceColor);
    //try to fill one step to the left
    FloodFill(new Point(node.X - 1, node.Y), targetColor, replaceColor);
    //try to fill one step to the north
    FloodFill(new Point(node.X, node.Y - 1), targetColor, replaceColor);
    //try to fill one step to the south
    FloodFill(new Point(node.X, node.Y + 1), targetColor, replaceColor);

    //exit method
    return;
  }
}
private void FloodFill(点节点、颜色targetColor、颜色replaceColor)
{
//执行边界检查X
如果((node.X>=CANVAS_SIZE)| |(node.X<0))
return;//超出范围
//执行边界检查
if((node.Y>=CANVAS_SIZE)| |(node.Y<0))
return;//超出边界
//检查节点是否为目标颜色
if(像素[node.X,node.Y].CellColor!=targetColor)
return;//返回,什么也不做
其他的
{
像素[node.X,node.Y].CellColor=replaceColor;
//重现
//尽量往右边走一步
泛光填充(新点(节点X+1,节点Y)、targetColor、replaceColor);
//试着往左边走一步
泛光填充(新点(node.X-1,node.Y)、targetColor、replaceColor);
//尽量往北走一步
泛光填充(新点(node.X,node.Y-1),targetColor,replaceColor);
//尽量往南边走一步
泛光填充(新点(节点X、节点Y+1)、targetColor、replaceColor);
//退出方法
返回;
}
}
接下来,我有一个使用基于队列的填充的方法。此方法在运行时导致OutOfMemory异常,并且在填充整个画布时速度非常慢。如果只填充画布的一小部分,则会有一定的效果:

private void QueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
  Queue<Point> points = new Queue<Point>();
  if (pixels[node.X, node.Y].CellColor != targetColor)
    return;

  points.Enqueue(node);

  while (points.Count > 0)
  {
    Point n = points.Dequeue();
    if (pixels[n.X, n.Y].CellColor == targetColor)
      pixels[n.X, n.Y].CellColor = replaceColor;

    if (n.X != 0)
    {
      if (pixels[n.X - 1, n.Y].CellColor == targetColor)
        points.Enqueue(new Point(n.X - 1, n.Y));
    }

    if (n.X != CANVAS_SIZE - 1)
    {
      if (pixels[n.X + 1, n.Y].CellColor == targetColor)
        points.Enqueue(new Point(n.X + 1, n.Y));
    }

    if (n.Y != 0)
    {
      if (pixels[n.X, n.Y - 1].CellColor == targetColor)
        points.Enqueue(new Point(n.X, n.Y - 1));
    }

    if (n.Y != CANVAS_SIZE - 1)
    {
      if (pixels[n.X, n.Y + 1].CellColor == targetColor)
        points.Enqueue(new Point(n.X, n.Y + 1));
    }
  }
  DrawCanvas();
  return;
}
private void QueueFloodFill(点节点、颜色targetColor、颜色replaceColor)
{
队列点=新队列();
if(像素[node.X,node.Y].CellColor!=targetColor)
返回;
点。排队(节点);
而(点数>0)
{
Point n=points.Dequeue();
if(像素[n.X,n.Y].CellColor==targetColor)
像素[n.X,n.Y].CellColor=replaceColor;
如果(n.X!=0)
{
if(像素[n.X-1,n.Y].CellColor==targetColor)
排队(新点(n.X-1,n.Y));
}
如果(n.X!=画布大小-1)
{
if(像素[n.X+1,n.Y].CellColor==targetColor)
点。排队(新点(n.X+1,n.Y));
}
如果(n.Y!=0)
{
if(像素[n.X,n.Y-1].CellColor==targetColor)
排队(新点(n.X,n.Y-1));
}
如果(n.Y!=画布尺寸-1)
{
if(像素[n.X,n.Y+1].CellColor==targetColor)
排队(新点(n.X,n.Y+1));
}
}
画布();
返回;
}
我尝试的最后一种方法也使用了基于队列的泛洪填充。此方法比以前基于队列的泛洪填充快得多,但最终也会在运行时导致OutOfMemory异常。同样,我尝试设置一个FillDelay计时器,以防止用户快速单击,但这仍然无法阻止异常的发生。另一个bug是,它很难正确填充小区域。在我能让它不崩溃之前,我认为没有必要修理它

private void RevisedQueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
  Queue<Point> q = new Queue<Point>();
  if (pixels[node.X, node.Y].CellColor != targetColor)
    return;

  q.Enqueue(node);
  while (q.Count > 0)
  {
    Point n = q.Dequeue();
    if (pixels[n.X, n.Y].CellColor == targetColor)
    {
      Point e = n;
      Point w = n;
      while ((w.X != 0) && (pixels[w.X, w.Y].CellColor == targetColor))
      {
        pixels[w.X, w.Y].CellColor = replaceColor;
        w = new Point(w.X - 1, w.Y);
      }

      while ((e.X != CANVAS_SIZE - 1) && (pixels[e.X, e.Y].CellColor == targetColor))
      {
        pixels[e.X, e.Y].CellColor = replaceColor;
        e = new Point(e.X + 1, e.Y);
      }

      for (int i = w.X; i <= e.X; i++)
      {
        Point x = new Point(i, e.Y);
        if (e.Y + 1 != CANVAS_SIZE - 1)
        {
          if (pixels[x.X, x.Y + 1].CellColor == targetColor)
            q.Enqueue(new Point(x.X, x.Y + 1));
        }
        if (e.Y - 1 != -1)
        {
          if (pixels[x.X, x.Y - 1].CellColor == targetColor)
            q.Enqueue(new Point(x.X, x.Y - 1));
        }
      }
    }
  }
}
private void RevisedQueueFloodFill(点节点、颜色targetColor、颜色replaceColor)
{
队列q=新队列();
if(像素[node.X,node.Y].CellColor!=targetColor)
返回;
q、 排队(节点);
而(q.Count>0)
{
点n=q.出列();
if(像素[n.X,n.Y].CellColor==targetColor)
{
点e=n;
点w=n;
而((w.X!=0)和&(像素[w.X,w.Y].CellColor==targetColor))
{
像素[w.X,w.Y].CellColor=replaceColor;
w=新点(w.X-1,w.Y);
}
而((e.X!=CANVAS_SIZE-1)和&(像素[e.X,e.Y].CellColor==targetColor))
{
像素[e.X,e.Y].CellColor=replaceColor;
e=新点(e.X+1,e.Y);
}
对于(inti=w.X;iOk)有两件事:

  • C#的递归限制(由堆栈大小决定)深度为几千。 这意味着您无法在不导致堆栈溢出的情况下深入递归。一旦方法返回,其指针就会从堆栈中弹出。您的问题与OutOfMemoryException不同。堆栈包含指针,而不是实际内存,因此并不意味着包含数千个指针

  • 垃圾回收是导致内存不足异常的原因。您需要停止在循环中声明变量。垃圾回收器将这些变量视为“仍在范围内”并且在循环完成所有迭代之前不会释放内存空间。但是如果使用相同的内存地址,每次都会覆盖它,几乎不会使用任何内存

  • 要明确的是:

    for (int i = w.X; i <= e.X; i++)
    {
        Point x = new Point(i, e.Y);
    }
    

    对于(int i=w.X;i在第三种方法中,您应该检查当前点正西方和东方的像素。而不是检查
    像素[w.X,w.Y]
    您应该检查
    像素[w.X-1,w.Y]
    而不是
    像素[e.X,e.Y]
    您应该有
    像素[e.X+1,e.Y]
    。以下是我对第三种方法的看法:

    private void RevisedQueueFloodFill(Point node, Color targetColor, Color replaceColor)
    {
        if (pixels[node.X, node.Y].CellColor != targetColor) return;
    
        Queue<Point> Q = new Queue<Point>();
        Q.Enqueue(node);
    
        while (Q.Count != 0)
        {
            Point n = Q.Dequeue();
            if (pixels[n.X, n.Y].CellColor == targetColor)
            {
                int y = n.Y;
                int w = n.X;
                int e = n.X;
                while (w > 0 && pixels[w - 1, y].CellColor == targetColor) w--;
                while (e < CANVAS_SIZE - 1 && pixels[e + 1, y].CellColor == targetColor) e++;
    
                for (int x = w; x <= e; x++)
                {
                    pixels[x, y].CellColor = replaceColor;
                    if (y > 0 && pixels[x, y - 1].CellColor == targetColor)
                    {
                        Q.Enqueue(new Point(x, y - 1));
                    }
                    if (y < CANVAS_SIZE - 1 && pixels[x, y + 1].CellColor == targetColor)
                    {
                        Q.Enqueue(new Point(x, y + 1));
                    }
                }
            }
        }
    }
    
    private void RevisedQueueFloodFill(点节点、颜色targetColor、颜色replaceColor)
    {
    if(像素[node.X,node.Y].CellColor!=targetColor)返回;
    队列Q=新队列();
    排队(节点);
    while(Q.Count!=0)
    {
    点n=Q.出列();
    if(像素[n.X,n.Y].CellColor==targetColor)
    {
    int y=n.y;
    int w=n.X;
    
    Point x;
    
    for(int i = w.X; i<= e.X; i++)
    {
       x = new Point(i, e.Y);
    }
    
    private void RevisedQueueFloodFill(Point node, Color targetColor, Color replaceColor)
    {
        if (pixels[node.X, node.Y].CellColor != targetColor) return;
    
        Queue<Point> Q = new Queue<Point>();
        Q.Enqueue(node);
    
        while (Q.Count != 0)
        {
            Point n = Q.Dequeue();
            if (pixels[n.X, n.Y].CellColor == targetColor)
            {
                int y = n.Y;
                int w = n.X;
                int e = n.X;
                while (w > 0 && pixels[w - 1, y].CellColor == targetColor) w--;
                while (e < CANVAS_SIZE - 1 && pixels[e + 1, y].CellColor == targetColor) e++;
    
                for (int x = w; x <= e; x++)
                {
                    pixels[x, y].CellColor = replaceColor;
                    if (y > 0 && pixels[x, y - 1].CellColor == targetColor)
                    {
                        Q.Enqueue(new Point(x, y - 1));
                    }
                    if (y < CANVAS_SIZE - 1 && pixels[x, y + 1].CellColor == targetColor)
                    {
                        Q.Enqueue(new Point(x, y + 1));
                    }
                }
            }
        }
    }
    
    private void RevisedQueueFloodFill(Point node, Color replaceColor)
    {
        Color targetColor = pixels[node.X, node.Y].CellColor;
        if (targetColor == replaceColor) return;
    
        Queue<Point> q = new Queue<Point>();
        q.Enqueue(node);
    
        Point n, t, u;
    
        while (q.Count > 0)
        {
            n = q.Dequeue();
            if (pixels[n.X, n.Y].CellColor == targetColor)
            {
    
                t = n;
                while ((t.X > 0) && (pixels[t.X, t.Y].CellColor == targetColor))
                {
                    pixels[t.X, t.Y].CellColor = replaceColor;
                    t.X--;
                }
                int XMin = t.X + 1;
    
    
                t = n;
                t.X++;
                while ((t.X < CANVAS_SIZE - 1) &&
                       (pixels[t.X, t.Y].CellColor == targetColor))
                {
                    pixels[t.X, t.Y].CellColor = replaceColor;
                    t.X++;
                }
                int XMax = t.X - 1;
    
                t = n;
                t.Y++;
    
                u = n;
                u.Y--;
    
                for (int i = XMin; i <= XMax; i++)
                {
                    t.X = i;
                    u.X = i;
    
                    if ((t.Y < CANVAS_SIZE - 1) &&
                        (pixels[t.X, t.Y].CellColor == targetColor)) q.Enqueue(t);
    
                    if ((u.Y >= 0) &&
                        (pixels[u.X, u.Y].CellColor == targetColor)) q.Enqueue(u);
                }
            }
        }
    }