Sort Algorithm Visualization: How to pull values to animate the canvas, from inside a tight loop

前端 未结 2 1442
小鲜肉
小鲜肉 2020-12-21 14:51

I am working on a visualization of different sorting algorithms using the height of different bars with tkinter. I have been able to shuffle the bars and also sort them afte

相关标签:
2条回答
  • 2020-12-21 15:07

    the time consuming function is "swap_two_pos()" which is catastrophic and you run it every loop, what you should do is finishing your sorting then redraw the bars again, below is your code modified working without GUI freeze, added a function and removed "swap_two_pos()" func.

    import tkinter as tk
    import random
    
    
    def insertion_sort():
        global barList
        global lengthList
    
        for i in range(len(lengthList)):
            cursor = lengthList[i]
            cursorBar = barList[i]
            pos = i
    
            while pos > 0 and lengthList[pos - 1] > cursor:
                lengthList[pos] = lengthList[pos - 1]
                barList[pos], barList[pos - 1] = barList[pos - 1], barList[pos]
                # canvas.after(1000,swap_two_pos(barList[pos],barList[pos-1]))
                pos -= 1
    
            lengthList[pos] = cursor
            barList[pos] = cursorBar
        refresh()
            # swap_two_pos(barList[pos],cursorBar)
    
    def refresh():
        canvas.delete('all')
        xstart = 5
        xend = 15
    
        for i, length in enumerate(lengthList): #range(1,60):
            y = random.randint(1,390)
            x = canvas.create_rectangle(xstart,length,xend,395, fill='red')
            barList.append(x)
            xstart += 10
            xend += 10
    
    
    def shuffle():
        global barList
        global lengthList
        canvas.delete('all')
        xstart = 5
        xend = 15
        barList = []
        lengthList = []
    
        for x in range(1,60):
            randomY = random.randint(1,390)
            x = canvas.create_rectangle(xstart,randomY,xend,395, fill='red')
            barList.append(x)
            xstart += 10
            xend += 10
    
        for bar in barList:
            x = canvas.coords(bar)
            length = x[3]-x[1]
            lengthList.append(length)
    
        for i in range(len(lengthList)-1):
            if lengthList[i] == min(lengthList):
                canvas.itemconfig(barList[i], fill='blue')
            elif lengthList[i] == max(lengthList):
                canvas.itemconfig(barList[i], fill='green')
    
    window = tk.Tk()
    window.title('Sorting')
    window.geometry('600x435')
    canvas = tk.Canvas(window, width='600', height='400')
    canvas.grid(column=0,row=0, columnspan = 50)
    
    insert = tk.Button(window, text='Insertion Sort', command=insertion_sort)
    shuf = tk.Button(window, text='Shuffle', command=shuffle)
    insert.grid(column=1,row=1)
    shuf.grid(column=0, row=1)
    
    shuffle()
    window.mainloop()
    
    0 讨论(0)
  • 2020-12-21 15:08

    Making use of a generator function (keyword yield), you can suspend the execution of the code mid loop to take the time to display the canvas elements that have changed, update calculations, etc., then resume the execution upon calling next on the generator repeatedly, until completion of the sort.

    I put some comments in the code, but the best way, is probably to stare at it until you convince yourself that it works as it is supposed to. This is a pattern that you need to understand, as it is very useful to construct the sort of animations you want to build.

    import tkinter as tk
    import random
    
    
    def swap_two_pos(pos_0, pos_1):
        Bar1x1, _, Bar1x2, _ = canvas.coords(pos_0)
        Bar2x1, _, Bar2x2, _ = canvas.coords(pos_1)
        canvas.move(pos_0, Bar2x1-Bar1x1, 0)
        canvas.move(pos_1, Bar1x2-Bar2x2, 0)
    
    
    def _insertion_sort():
        global barList
        global lengthList
    
        for i in range(len(lengthList)):
            cursor = lengthList[i]
            cursorBar = barList[i]
            pos = i
    
            while pos > 0 and lengthList[pos - 1] > cursor:
                lengthList[pos] = lengthList[pos - 1]
                barList[pos], barList[pos - 1] = barList[pos - 1], barList[pos]
                swap_two_pos(barList[pos],barList[pos-1])   # <-- updates the display
                yield                                       # <-- suspends the execution
                pos -= 1                                    # <-- execution resumes here when next is called
    
            lengthList[pos] = cursor
            barList[pos] = cursorBar
            swap_two_pos(barList[pos],cursorBar)
    
    
    worker = None    # <-- Not a thread in spite of the name.
    
    def insertion_sort():     # <-- commands the start of both the animation, and the sort
        global worker
        worker = _insertion_sort()
        animate()
    
    
    def animate():      # <-- commands resuming the sort once the display has been updated
                        # controls the pace of the animation
        global worker
        if worker is not None:
            try:
                next(worker)
                window.after(10, animate)    # <-- repeats until the sort is complete,
            except StopIteration:            # when the generator is exhausted
                worker = None
            finally:
                window.after_cancel(animate) # <-- stop the callbacks
    
    
    def shuffle():
        global barList
        global lengthList
        canvas.delete('all')
        xstart = 5
        xend = 15
        barList = []
        lengthList = []
    
        for x in range(1, 60):
            randomY = random.randint(1, 390)
            x = canvas.create_rectangle(xstart, randomY, xend, 395, fill='red')
            barList.append(x)
            xstart += 10
            xend += 10
    
        for bar in barList:
            x = canvas.coords(bar)
            length = x[3] - x[1]
            lengthList.append(length)
    
        for i in range(len(lengthList)-1):
            if lengthList[i] == min(lengthList):
                canvas.itemconfig(barList[i], fill='blue')
            elif lengthList[i] == max(lengthList):
                canvas.itemconfig(barList[i], fill='green')
    
    
    window = tk.Tk()
    window.title('Sorting')
    window.geometry('600x435')
    canvas = tk.Canvas(window, width='600', height='400')
    canvas.grid(column=0,row=0, columnspan = 50)
    
    insert = tk.Button(window, text='Insertion Sort', command=insertion_sort)
    shuf = tk.Button(window, text='Shuffle', command=shuffle)
    insert.grid(column=1,row=1)
    shuf.grid(column=0, row=1)
    
    shuffle()
    window.mainloop()
    
    0 讨论(0)
提交回复
热议问题