优化,替换递归或只是修复大规模递归中的错误。

huangapple go评论73阅读模式
英文:

Optimize, replace recursion or just fix error with mass recursion

问题

以下是您提供的代码的翻译:

我在Python中遇到了递归深度的问题我想知道如何使它更高效或替代它或增加递归深度

我尝试通过 `sys.setrecursionlimit` 来增加递归深度但没有结果它每次都停在 990

基本上我正在为我的Tkinter迷你绘图程序制作泛洪填充在小区域上它填充得非常好但在大区域上会出现错误 `RecursionError: maximum recursion depth exceeded in __instancecheck__`。

此外还有以下代码

```py
import tkinter as tk
from random import randint, seed

# 请忽略这些全局变量
blocks = 100
block_size = 5
res = (block_size * blocks,) * 2
color = 'a'
color_dict = {}

class MainWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.resizable(False, False)
        self.c = tk.Canvas(self, width=res[0], height=res[1], highlightthickness=0, bg='white')
        self.c.grid(sticky='w')
        self.title('主窗口')
        self.bind("<Key>", self.key_handler)
        # b-motion是按住按钮并移动时的事件
        self.bind("<B1-Motion>", self.left_click)
        self.bind("<Button-1>", self.left_click)
        self.bind("<B3-Motion>", self.right_click)
        self.bind("<Button-3>", self.right_click)
        self.field = [[0] * blocks for i in range(blocks)]
        self.is_flood_fill = False

    # 创建块
    def create_block(self, x, y, size, fill='white'):
        self.c.create_rectangle(x, y, x + size, y + size, fill=fill, outline='')

    def key_handler(self, event):
        print(event.keycode)
        match event.keycode:
            case 82: self.is_flood_fill = False if self.is_flood_fill else True

    # 左键单击处理程序
    def left_click(self, event):
        if self.is_flood_fill:
            col, row = self.get_field_pos(event.x, event.y)
            self.flood_fill(col, row, self.field[row][col], color)
        else: self.draw(event.x, event.y, color)

    # 右键单击处理程序
    def right_click(self, event): self.draw(event.x, event.y, 0)

    def draw(self, cursor_x, cursor_y, color):
        col, row = self.get_field_pos(cursor_x, cursor_y)
        if self.field[row][col] != color:
            try: print(self.field[row][col]);self.field[row][col] = color; print(self.field[row][col])
            except Exception: pass; print(Exception)
            self.create_block(col * block_size, row * block_size, block_size, self.color_case(color))

    def get_field_pos(self, x, y): return ((round(x / block_size), round(y / block_size)))

    # 从字典中获取颜色,如果不存在则生成,并放入同一字典
    def color_case(self, code):
        global color
        if code == 0: return 'white'
        elif not code in color_dict:
            # 使用代码生成随机种子
            seed(code)
            # 生成十六进制颜色
            r = lambda: randint(0, 255)
            color_dict[code] = '#{0:02X}{1:02X}{2:02X}'.format(r(), r(), r())
        return color_dict[code]

    # 主要问题在于这里
    def flood_fill(self, col, row, old_color, new_color):
        # 检查
        if col < 0 or col >= blocks or row < 0 or row >= blocks: return
        if self.field[row][col] != old_color: return

        self.field[row][col] = new_color
        self.create_block(col * block_size, row * block_size, block_size, self.color_case(color))
        # 尝试填充相邻位置
        self.flood_fill(col + 1, row, old_color, new_color)
        self.flood_fill(col - 1, row, old_color, new_color)
        self.flood_fill(col, row + 1, old_color, new_color)
        self.flood_fill(col, row - 1, old_color, new_color)

if __name__ == "__main__":
    app = MainWindow()
    app.mainloop()

希望这个翻译对您有所帮助。如果您有任何其他问题,请随时提出。

英文:

I have problem with recursion depth in Python. I want to know how to make it efficient or replace it, or make recursion depth larger.

I tried make it larger by sys.setrecursionlimit, but no result. It's stopping on 990 every time.

Basicly, I making flood fill for my mini-paint program on Tkinter.
On small fields it's fill prefectly fine, but on larger there error RecursionError: maximum recursion depth exceeded in __instancecheck__

Also, there code:

import tkinter as tk
from random import randint, seed

# don&#39;t mind me about these global vars
blocks = 100
block_size = 5
res = (block_size*blocks,)*2
color = &#39;a&#39;
color_dict = {}

class MainWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.resizable(False,False)
        self.c = tk.Canvas(self, width=res[0], height=res[1], highlightthickness=0, bg=&#39;white&#39;)
        self.c.grid(sticky=&#39;w&#39;)
        self.title(&#39;Main Window&#39;)
        self.bind(&quot;&lt;Key&gt;&quot;, self.key_handler)
        # b-motion is when holding button and moving
        self.bind(&quot;&lt;B1-Motion&gt;&quot;, self.left_click)
        self.bind(&quot;&lt;Button-1&gt;&quot;, self.left_click)
        self.bind(&quot;&lt;B3-Motion&gt;&quot;, self.right_click)
        self.bind(&quot;&lt;Button-3&gt;&quot;, self.right_click)
        self.field = [[0]*blocks for i in range(blocks)]
        self.is_flood_fill = False

    # creating block
    def create_block(self, x, y, size, fill=&#39;white&#39;): 
        self.c.create_rectangle(x,y,x+size,y+size,fill=fill,outline=&#39;&#39;)

    def key_handler(self, event):
        print(event.keycode)
        match event.keycode:
            case 82: self.is_flood_fill=False if self.is_flood_fill else True
    
    # left click handler
    def left_click(self, event):
        if self.is_flood_fill:
            col,row=self.get_field_pos(event.x, event.y)
            self.flood_fill(col, row, self.field[row][col], color)
        else: self.draw(event.x, event.y, color)

    # right click handler
    def right_click(self, event): self.draw(event.x, event.y, 0)

    def draw(self, cursor_x, cursor_y, color):
        col,row=self.get_field_pos(cursor_x, cursor_y)
        if self.field[row][col] != color:
            try: print(self.field[row][col]);self.field[row][col] = color; print(self.field[row][col])
            except Exception: pass; print(Exception)
            self.create_block(col*block_size, row*block_size, block_size, self.color_case(color))

    def get_field_pos(self, x, y): return((round(x/block_size), round(y/block_size)))

    # grabing color from dict, or generating if it&#39;s not there and puting in same dict
    def color_case(self, code):
        global color
        if code == 0: return &#39;white&#39;
        elif not code in color_dict:
            # seed of random by code
            seed(code)
            # generating hex color
            r = lambda: randint(0,255)
            color_dict[code] = &#39;#%02X%02X%02X&#39; % (r(),r(),r())
        return color_dict[code]

    # main problem is there
    def flood_fill(self,col,row,old_color,new_color):
        # checks
        if col &lt; 0 or col &gt;= blocks or row &lt; 0 or row &gt;= blocks: return
        if self.field[row][col] != old_color: return

        self.field[row][col] = new_color
        self.create_block(col*block_size, row*block_size, block_size, self.color_case(color))
        # attempt to fill the neighboring positions
        self.flood_fill(col+1, row, old_color, new_color)
        self.flood_fill(col-1, row, old_color, new_color)
        self.flood_fill(col, row+1, old_color, new_color)
        self.flood_fill(col, row-1, old_color, new_color)

if __name__ == &quot;__main__&quot;:
    app = MainWindow()
    app.mainloop()

答案1

得分: 0

你可以将递归转换为使用显式栈(列表)。其次,当旧颜色和新颜色相同时,应跳过整个过程,否则你将陷入循环并最终耗尽内存。

def flood_fill(self, col, row, old_color, new_color):
    if old_color == new_color:
        return
    stack = [(col, row)]
    while stack:
        col, row = stack.pop()
        if 0 <= col < blocks and 0 <= row < blocks and self.field[row][col] == old_color:
            self.field[row][col] = new_color
            self.create_block(col*block_size, row*block_size, block_size, self.color_case(color))
            stack.extend([(col+1, row), (col-1, row), (col, row+1), (col, row-1)])
英文:

You could convert the use of recursion into using an explicit stack (list). Secondly, you should skip the whole thing when the old and new color are equal, as otherwise you'll keep running in circles and eventually run out of memory.

def flood_fill(self, col, row, old_color, new_color):
if old_color == new_color:
return
stack = [(col, row)]
while stack:
col, row = stack.pop()
if 0 &lt;= col &lt; blocks and 0 &lt;= row &lt; blocks and self.field[row][col] == old_color:
self.field[row][col] = new_color
self.create_block(col*block_size, row*block_size, block_size, self.color_case(color))
stack.extend([(col+1, row), (col-1, row), (col, row+1), (col, row-1)])

huangapple
  • 本文由 发表于 2023年6月26日 22:32:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76557670.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定