[英]Sort Algorithm Visualization: How to pull values to animate the canvas, from inside a tight loop
我正在使用tkinter使用不同条形的高度来可视化不同排序算法。 我已经能够重新整理酒吧,并在得到一些帮助后对其进行排序。 我现在遇到的问题是减慢条形的排序速度,因此可以看出每种算法的工作原理。 这是我到目前为止的内容:
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]
canvas.after(1000,swap_two_pos(barList[pos],barList[pos-1]))
pos -= 1
lengthList[pos] = cursor
barList[pos] = cursorBar
swap_two_pos(barList[pos],cursorBar)
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()
如您所见,我尝试在插入排序函数中使用after()
方法,但是它所做的只是冻结窗口并使其不响应。 如果没有该方法,它将无法正常工作,只是步伐不明显。
利用生成器函数(关键字yield
),您可以暂停代码中间循环的执行,以花时间显示已更改的画布元素,更新计算等,然后在调用生成器中的next
时恢复执行反复,直到排序完成。
我在代码中添加了一些注释,但是最好的方法可能是盯着它,直到您确信自己可以按预期工作为止。 这是您需要了解的一种模式,因为它对构造您想要构建的动画非常有用。
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()
耗时的函数是“ swap_two_pos()”,这是灾难性的,您需要在每个循环中运行它,您应该做的是完成排序,然后重新绘制条形图,下面是修改后的代码,不冻结GUI,添加了一个函数,并删除了它swap_two_pos()”功能。
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()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.