递归转迭代实操记录

针对那些经典的像素游戏设计的自动切图工具里用到种子填充算法的实现。算法

一开始是用递归实现的,后来遇到一些头像之类的比较大一点的图素,运行的时候常常占满C#默认的1M线程栈内存而崩溃。尝试使用各类多线方式改造并无成功,因而干脆改为迭代形式,建立一个Stack本身彻底精确控制其中的数据操做。多线程

这里截取一段改为迭代后的代码,这是窗体的事件处理用cs代码。由于只是个小工具,没有彻底把界面和逻辑分离。app

//堆栈最大深度 private const int MaxStackFrames = 640 * 480; private Stack<FillStackFrame> mStack = new Stack<FillStackFrame>(MaxStackFrames); private void fillRegion(int x, int y) { //防止多线程操做堆栈引发的问题 lock (this) { //从UI初始化本次调用不会变的参数 int distance = Convert.ToInt32(txtDistance.Text); //复位堆栈而且压入初始数据 mStack.Clear(); var frame = new FillStackFrame(); frame.x = x; frame.y = y; mStack.Push(frame); //堆栈为空即全部链接区域被填充完毕,执行结束 while (mStack.Count > 0) { //弹出堆栈数据 var popped = mStack.Pop(); x = popped.x; y = popped.y; //递归终止条件1 遇到填充区域越界 if (x < 0 || y < 0 || x >= srcImg.Width || y >= srcImg.Height) continue; //递归终止条件2 遇到背景色,或者已搜索像素 if (!isTransparent(srcImg, x, y) && tmpImg.GetPixel(x, y).A != 255) { tmpImg.SetPixel(x, y, fillColor); if (maxX < x) maxX = x; if (minX > x) minX = x; if (maxY < y) maxY = y; if (minY > y) minY = y; for (int i = 1; i <= distance; ++i) { if (mStack.Count >= MaxStackFrames) throw new StackOverflowException("填充蒙版时堆栈溢出!"); //八个方向延伸搜索,这里的全部堆栈Push操做换回FillRegion方法的调用,就是本来的递归写法了 mStack.Push(new FillStackFrame() { x = x - i, y = y}); mStack.Push(new FillStackFrame() { x = x + i, y = y}); mStack.Push(new FillStackFrame() { x = x, y = y - i}); mStack.Push(new FillStackFrame() { x = x, y = y + i}); mStack.Push(new FillStackFrame() { x = x - i, y = y - i}); mStack.Push(new FillStackFrame() { x = x + i, y = y + i}); mStack.Push(new FillStackFrame() { x = x - i, y = y + i}); mStack.Push(new FillStackFrame() { x = x + i, y = y - i}); } } } } }

总结一下递归转迭代的操做步骤:函数

  1. 初始化函数调用前用到的类的成员变量和常量,放在类的成员变量或者常量直接初始化就能够。
  2. 初始化在本次调用不变的数据好比这里的延伸距离distance,放在进入迭代循环以前。
  3. 把递归函数的参数合成一个类型Frame,建立一个Stack<Frame>来代替运行时提供的栈内存。这个Stack根据具体状况能够是类的成员变量也能够是函数的局部变量。
  4. 压入初始的传入参数帧
  5. 进入迭代循环,迭代循环基本就是本来函数的递归执行体改造过来。
  6. 迭代循环中把全部递归调用自身的函数换成新参数构建成帧而且压入Stack。
  7. 原有的return改为对迭代循环的continue。
  8. 若是有跳出全部原来递归的须要,在迭代循环中加入break。
  9. 其余操做顺序维持不变。
相关文章
相关标签/搜索