当前位置: 首页 > 编程语言 > C#

FloodFill的不同实现方式分享

时间:2023-04-11 00:32:46 C#

所有这些都可能导致问题。我将列出3种方法并解释每种方法会发生什么。如果有人能给我一些很好的指示。我看过一些类似的帖子,但没有一个是针对C#、java或VB.net(我知道的唯一语言)的。这样做的好处是我有一个名为PixelData的类,它将Color存储在CellColor成员变量中。我有一个名为“像素”的50x50PixelData对象数组。我还有一个名为CANVAS_SIZE的常量,在本例中为50。以下是我尝试过的三种方法。这个是递归的。它很容易发生堆栈溢出。我已经尝试设置一个计时器,在此方法完成后启用CanFill成员。这仍然不能防止溢出:privatevoidFloodFill(Pointnode,ColortargetColor,ColorreplaceColor){//执行边界检查Xif((node.X>=CANVAS_SIZE)||(node.X=CANVAS_SIZE)||(node.Y<0))返回;//超出边界//检查节点是否为目标颜色if(pixels[node.X,node.Y].CellColor!=targetColor)return;//返回并且什么都不做{pixels[node.X,node.Y].CellColor=replaceColor;//递归//尝试向右填充一步FloodFill(newPoint(node.X+1,node.Y),targetColor,replaceColor);//尝试向左填充一级FloodFill(newPoint(node.X-1,node.Y),targetColor,replaceColor);//尝试向北填充一级FloodFill(newPoint(node.X,node.Y-1),targetColor,replaceColor);//尝试向南填充一级FloodFill(newPoint(node.X,node.Y+1),targetColor,replaceColor);//退出方法返回;接下来,我有一个使用基于队列的填充的方法。此方法会在运行时导致OutOfMemory异常,并且在填充整个画布时速度非常慢。如果你只填充画布的一小部分,它会有点效率:privatevoidQueueFloodFill(Pointnode,ColortargetColor,ColorreplaceColor){如果(像素[node.X,node.Y].CellColor!=targetColor)返回;points.Enqueue(节点);while(points.Count>0){Pointn=points.Dequeue();如果(像素[nX,nY].CellColor==targetColor)像素[nX,nY].CellColor=replaceColor;if(nX!=0){if(pixels[nX-1,nY].CellColor==targetColor)points.Enqueue(newPoint(nX-1,nY));}if(nX!=CANVAS_SIZE-1){if(pixels[nX+1,nY].CellColor==targetColor)points.Enqueue(newPoint(nX+1,nY));}if(nY!=0){if(pixels[nX,nY-1].CellColor==targetColor)points.Enqueue(newPoint(nX,nY-1));}if(nY!=CANVAS_SIZE-1){if(pixels[nX,nY+1].CellColor==targetColor)points.Enqueue(newPoint(nX,nY+1));}}DrawCanvas();返回;我尝试的最后一种方法也使用基于队列的floodfill。这种方法比以前基于队列的floodfill快得多,但也会在运行时导致OutOfMemoryexception。同样,我已经尝试设置一个FillDelay计时器来防止用户点击得太快,但这仍然不能阻止异常的发生。这个问题的另一个缺点是很难正确填充小区域。在我让它不崩溃之前,我认为没有必要解决这个问题。privatevoidRevisedQueueFloodFill(Pointnode,ColortargetColor,ColorreplaceColor){Queueq=newQueue();如果(pixels[node.X,node.Y].CellColor!=targetColor)返回;q.入队(节点);while(q.Count>0){点n=q.Dequeue();if(pixels[nX,nY].CellColor==targetColor){点e=n;点w=n;while((wX!=0)&&(像素[wX,wY].CellColor==targetColor)){像素[wX,wY].CellColor=replaceColor;w=新点(wX-1,wY);}while((eX!=CANVAS_SIZE-1)&&(pixels[eX,eY].CellColor==targetColor)){pixels[eX,eY].CellColor=replaceColor;e=新点(eX+1,eY);}for(inti=wX;i<=eX;i++){Pointx=newPoint(i,eY);if(eY+1!=CANVAS_SIZE-1){if(pixels[xX,xY+1].CellColor==targetColor)q.Enqueue(newPoint(xX,xY+1));}if(eY-1!=-1){if(pixels[xX,xY-1].CellColor==targetColor)q.Enqueue(newPoint(xX,xY-1));}}}}}感谢大家的帮助!所有这些方法都基于维基百科上的伪代码。编辑:我选择了RevisedQueueFloodFill并按照建议进行了修改,以便不在循环中声明该变量。仍在生成OutOfMemory。即使有filldelay计时器。privatevoidRevisedQueueFloodFill(Pointnode,ColortargetColor,ColorreplaceColor){Queueq=newQueue();如果(像素[节点。X,节点。Y]。CellColor!=targetColor)返回;q.入队(节点);点n、e、w、x;while(q.Count>0){n=q.出列();if(pixels[nX,nY].CellColor==targetColor){e=n;w=n;while((wX!=0)&&(pixels[wX,wY].CellColor==targetColor)){pixels[wX,wY].单元格颜色=替换颜色;w=新点(wX--1,wY);}while((eX!=CANVAS_SIZE--1)&&(pixels[eX,eY].CellColor==targetColor)){pixels[eX,eY].CellColor=replaceColor;e=新点(eX+1,eY);}for(inti=wX;i<=eX;i++){x=newPoint(i,eY);if(eY+1!=CANVAS_SIZE-1){if(pixels[xX,xY+1].CellColor==targetColor)q。排队(新点(xX,xY+1));}if(eY-1!=-1){if(pixels[xX,xY-1].CellColor==targetColor)q.Enqueue(newPoint(xX,xY-1));}}}}}原文,具体来说:C3是最常见的雪花类型(basicsnowflakes)。这意味着您不能在不导致堆栈溢出的情况下向下递归DEEPER。一旦方法返回,它的指针就会从堆栈中弹出。您的问题与OutOfMemoryException不同。堆栈保存指针而不是实际内存,因此它并不意味着有数千个指针。垃圾收集是内存不足的原因。您需要停止在循环内声明变量。垃圾收集器将这些视为“仍在范围内”,并且在循环完成所有迭代之前不会释放内存空间。但是如果你使用相同的内存地址,它每次都会覆盖它,几乎不使用任何内存。要清楚:for(inti=wX;i应该是这样的:Pointx;for(inti=wX;i这将重用你想要的内存地址。希望有帮助!我不知道这是否可能,但我自己怀疑由于所有“新”运算符,使用的内存比必要的多得多,并且可能由于算法的密集性质,垃圾收集器没有机会比赛?我重写了算法,所以所有Point变量都被重用了,但我暂时没有办法测试这个。我会冒昧地改变前几行代码,但那是因为一个未成年人我的烦恼,因为你会发现大多数洪水填充算法都需要用户指定目标颜色,事实上你可以从参数中给定的点自动获取目标颜色。无论如何,尝试使用它,或者只是模拟它:privatevoidRevisedQueueFloodFill(Pointnode,ColorreplaceColor){如果(targetColor==replaceColor)返回;队列q=新队列();q.入队(节点);点n、t、u;while(q.Count>0){n=q.Dequeue();如果(像素[nX,nY].CellColor==targetColor){t=n;while((tX>0)&&(像素[tX,tY].CellColor==targetColor)){像素[tX,tY].CellColor=replaceColor;tX--;}intXMin=tX+1;t=n;t.X++;while((tX=0)&&(pixels[uX,uY].CellColor==targetColor))q.Enqueue(u);}}}}在第三种方法中,您应该检查当前点西边和东边的像素。您应该检查pixels[wX-1,wY]而不是pixels[eX,eY]而不是检查pixels[eX+1,eY]。这是我对你的第三种方法的看法:队列Q=新队列();Q.入队(节点);while(Q.Count!=0){点n=Q.Dequeue();if(pixels[nX,nY].CellColor==targetColor){inty=nY;intw=nX;整数e=nX;while(w>0&&pixels[w-1,y].CellColor==targetColor)w--;while(e0&&pixels[x,y-1].CellColor==targetColor){Q.Enqueue(newPoint(x,y-1));}if(y这里使用基本算法的问题在于,你正在对一个点进行多次访问并进行广度优先搜索。这意味着你在每次传递期间创建了同一个点的多个副本。这会呈指数累积,因为每个点都可以传播(排队更多点),即使它不是目标颜色(已经被替换)。在设置颜色(而不是在出队)时对它们进行排队之后,这样您就不会最终添加它们totheQueuetwice以上就是C#学习教程的全部内容:FloodFill的不同实现方式,如果对大家有用需要了解更多C#学习教程,希望大家多多关注---这篇文章整理自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除,如需转载请注明出处: