Gnome sort

类别:排序-交换排序
参看 维基百科的定义

 

Gnome sort is a sorting algorithm which is similar to insertion sort, except that moving an element to its proper place is accomplished by a series of swaps, as in bubble sort. The name comes from the supposed behavior of the Dutch garden gnome in sorting a line of flowerpots and is described on Dick Grune's Gnome sort page.

 


import tkinter as tk from tkinter import ttk, filedialog, messagebox from PIL import Image, ImageTk, ImageSequence import pandas as pd import time import os import random import threading import queue from bubble import Bubble from selection import Selection from insertion import Insertion from shellsort import Shell from cocktailsort import Cocktail from gnomesort import Gnome from combsort import Comb from countingsort import Counting from radixsort import Radix from bucketsort import Bucket from timsort import Tim from heapsort import Heap from quicksort import Quick from mergesort import Merge window = tk.Tk() window.title("排序方法") window.geometry("1200x800+300+100") # 全局变量声明 current_file = "" arr = [] filename = "sort.csv" gif_label = None gif_frames = [] gif_index = 0 gif_speed = 150 gif_after_id = None scroll_after_id = None BATCH_SIZE = 10000 display_queue = queue.Queue() is_displaying = False sorting_thread = None sorting_active = False def load_gif(file_path, size=(400, 300)): # 加载gif global gif_frames, gif_index # 声明全局变量 gif_frames = [] try: img = Image.open(file_path) for frame in ImageSequence.Iterator(img): resized = frame.copy().resize(size, Image.Resampling.LANCZOS) gif_frames.append(ImageTk.PhotoImage(resized)) gif_index = 0 return bool(gif_frames) except Exception as e: print(f"加载 GIF 出错: {e}") return False def animate_gif(): # 循环显示gif的每一帧 global gif_index, gif_after_id if gif_frames: gif_label.config(image=gif_frames[gif_index]) gif_index = (gif_index + 1) % len(gif_frames) gif_after_id = window.after(gif_speed, animate_gif) def update_gif(file_path): global gif_after_id, gif_frames, gif_index if gif_after_id: window.after_cancel(gif_after_id) if load_gif(file_path, size=(500, 300)): animate_gif() else: gif_label.config(text=f"GIF 加载失败: {file_path}") def load_file(): file_path = filedialog.askopenfilename( title="选择数据文件", filetypes=[("CSV文件", "*.csv"), ("文本文件", "*.txt"), ("所有文件", "*.*")] ) if file_path: status_label.config(text=f"正在加载文件: {os.path.basename(file_path)}...") window.update() threading.Thread(target=load_data_thread, args=(file_path), daemon=True).start() def load_data_thread(file_path): global arr, current_file # 声明全局变量 try: # 分块读取大文件 chunks = [] total_size = os.path.getsize(file_path) processed = 0 for chunk in pd.read_csv(file_path, chunksize=10000): chunks.append(chunk) processed += chunk.memory_usage(index=True, deep=True).sum() progress_value = min(processed / total_size * 100, 100) window.after(0, update_progress, progress_value, f"加载中: {progress_value:.1f}% ({processed / 1e6:.2f}MB/{total_size / 1e6:.2f}MB)") df = pd.concat(chunks) arr = df.values.flatten().tolist() current_file = os.path.basename(file_path) # 更新UI window.after(0, update_treeview_batch, unsort_tree, arr) window.after(0, update_treeview, sort_tree, []) window.after(0, lambda: status_label.config( text=f"已加载: {len(arr)} 条数据 | 文件: {current_file}")) window.after(0, lambda: progress.configure(value=0)) except Exception as e: window.after(0, lambda: messagebox.showerror("错误", f"加载文件失败: {str(e)}")) window.after(0, lambda: status_label.config(text=f"加载失败: {str(e)}")) def update_treeview(treeview, data): treeview.delete(*treeview.get_children()) for value in data: treeview.insert("", "end", values=(value,)) def update_treeview_batch(treeview, data): """分批更新Treeview控件""" treeview.delete(*treeview.get_children()) total = len(data) def add_batch(start_idx=0): end_idx = min(start_idx + BATCH_SIZE, total) for i in range(start_idx, end_idx): treeview.insert("", "end", values=(data[i],)) # 更新进度 progress_value = end_idx / total * 100 window.after(0, lambda: progress.configure(value=progress_value)) if end_idx < total: # 使用计时器安排下一批处理 treeview.after(1, add_batch, end_idx) else: treeview.yview_moveto(1.0) add_batch(0) def scroll_sorted_data(treeview, data): """分批滚动显示排序结果""" global scroll_after_id if scroll_after_id: window.after_cancel(scroll_after_id) treeview.delete(*treeview.get_children()) total = len(data) progress.configure(value=0) def scroll(index=0): # 一次插入一批数据 batch_size = min(BATCH_SIZE, total - index) for i in range(index, index + batch_size): treeview.insert("", "end", values=(data[i],)) # 滚动到底部 treeview.yview_moveto(1.0) # 更新进度 progress_value = (index + batch_size) / total * 100 window.after(0, lambda: progress.configure(value=progress_value)) if index + batch_size < total: # 使用计时器安排下一批显示 scroll_after_id = treeview.after(1, scroll, index + batch_size) else: scroll_after_id = None scroll(0) def generate_random_data(): global arr try: count = int(entry.get()) if count < 100: messagebox.showerror("错误", "请输入100以上的数字") return # 清空现有数组 arr = [] # 更新状态 status_label.config(text=f"正在生成 {count} 条随机数据...") window.update() # 启动线程生成数据 threading.Thread(target=generate_data_thread, args=(count,), daemon=True).start() except ValueError: messagebox.showerror("错误", "请输入有效的数字") def generate_data_thread(count): global arr, current_file, stop_sorting arr = [] # 确保数组为空 stop_sorting = False # 分批生成数据 for i in range(0, count, BATCH_SIZE): batch_size = min(BATCH_SIZE, count - len(arr)) batch = [] for _ in range(batch_size): rand_type = random.choice(["int", "float"]) # 控制整数和浮点数的比例 if len(arr) < count * 0.7: # 70% 整数 batch.append(random.randint(-100000, 100000)) else: batch.append(round(random.uniform(-100000, 100000), 3)) arr.extend(batch) # 更新进度 progress_value = len(arr) / count * 100 window.after(0, lambda: update_progress(progress_value, f"生成进度: {progress_value:.1f}% ({len(arr)}/{count})")) # 保存数据 current_file = "random_data.csv" pd.DataFrame(arr).to_csv(current_file, index=False) # 更新UI window.after(0, lambda: update_treeview_batch(unsort_tree, arr)) window.after(0, lambda: update_treeview(sort_tree, [])) window.after(0, lambda: status_label.config( text=f"已生成 {len(arr)} 条随机数据并保存")) window.after(0, lambda: progress.configure(value=0)) def start_sorting(): global sorting_active # 声明全局变量 if not arr: messagebox.showwarning("警告", "没有数据可排序") return if sorting_active: messagebox.showwarning("警告", "排序正在进行中") return # 更新状态 sorting_active = True algorithm = var.get() algorithm_name = { "bubblesort": "冒泡排序", "selectionsort": "选择排序", "insertionsort": "插入排序", "quicksort": "快速排序", "mergesort": "归并排序", "shellsort": "希尔排序", "cocktailsort": "鸡尾酒排序", "gnomesort": "侏儒排序", "combsort": "梳排序", "countingsort": "计数排序", "radixsort": "基数排序", "bucketsort": "桶排序", "timsort": "Tim排序", "heapsort": "堆排序" }.get(algorithm, algorithm) time_label.config(text="排序耗时: 计算中...") steps_label.config(text="运算步数: 计算中...") result_label.config(text="结果文件: 处理中...") status_label.config(text=f"正在使用 {algorithm_name} 排序数据...") progress.configure(value=0) window.update() # 创建新线程运行排序算法 sorting_thread = threading.Thread(target=choose, daemon=True) sorting_thread.start() def choose(): global sorting_active # 声明全局变量 arr_copy = arr.copy() start_time = time.time() algorithm = var.get() sorted_arr, steps = None, 0 title = "" try: if algorithm == "bubblesort": sorter = Bubble() sorted_arr, steps = sorter.sort(arr_copy) title = "冒泡排序" elif algorithm == "selectionsort": sorter = Selection() sorted_arr, steps = sorter.sort(arr_copy) title = "选择排序" elif algorithm == "insertionsort": sorter = Insertion() sorted_arr, steps = sorter.sort(arr_copy) title = "插入排序" elif algorithm == "quicksort": sorter = Quick() sorted_arr, steps = sorter.sort(arr_copy) title = "快速排序" elif algorithm == "mergesort": sorter = Merge() sorted_arr, steps = sorter.sort(arr_copy) title = "归并排序" elif algorithm == "shellsort": sorter = Shell() sorted_arr, steps = sorter.sort(arr_copy) title = "希尔排序" elif algorithm == "cocktailsort": sorter = Cocktail() sorted_arr, steps = sorter.sort(arr_copy) title = "鸡尾酒排序" elif algorithm == "gnomesort": sorter = Gnome() sorted_arr, steps = sorter.sort(arr_copy) title = "侏儒排序" elif algorithm == "combsort": sorter = Comb() sorted_arr, steps = sorter.sort(arr_copy) title = "梳排序" elif algorithm == "countingsort": sorter = Counting() sorted_arr, steps = sorter.sort(arr_copy) title = "计数排序" elif algorithm == "radixsort": sorter = Radix() sorted_arr, steps = sorter.sort(arr_copy) title = "基数排序" elif algorithm == "bucketsort": sorter = Bucket() sorted_arr, steps = sorter.sort(arr_copy) title = "桶排序" elif algorithm == "timsort": sorter = Tim() sorted_arr, steps = sorter.sort(arr_copy) title = "Tim排序" elif algorithm == "heapsort": sorter = Heap() sorted_arr, steps = sorter.sort(arr_copy) title = "堆排序" else: sorter = Bubble() sorted_arr, steps = sorter.sort(arr_copy) title = "冒泡排序" elapsed_time = time.time() - start_time # 保存结果 with open(filename, "a", encoding="utf-8") as f: # 使用"w"模式覆盖旧文件 f.write(f"\n{title}\n") f.write("\n".join(map(str, sorted_arr))) # 更新UI window.after(0, lambda: scroll_sorted_data(sort_tree, sorted_arr)) window.after(0, lambda: time_label.config( text=f"排序耗时: {elapsed_time:.4f} 秒")) window.after(0, lambda: steps_label.config( text=f"运算步数: {steps}")) window.after(0, lambda: result_label.config( text=f"结果文件: {os.path.abspath(filename)}")) window.after(0, lambda: status_label.config( text=f"{title} 完成! 已处理 {len(arr)} 条数据")) except Exception as e: window.after(0, lambda: messagebox.showerror("排序错误", f"排序过程中出错: {str(e)}")) window.after(0, lambda: status_label.config( text=f"排序失败: {str(e)}")) finally: sorting_active = False progress.configure(value=100) def stop_processing(): stop_sorting = True status_label.config(text="正在停止当前操作...") def on_combobox_select(event=None): algorithm = var.get() gif_map = { "bubblesort": "bubble.gif", "selectionsort": "sele.gif", "insertionsort": "inster.gif", "quicksort": "quick.gif", "mergesort": "merge.gif", "shellsort":"shell.gif", "cocktailsort": "cocktail.gif", "gnomesort": "gnome.gif", "combsort": "comb.gif", "countingsort": "counting.gif", "radixsort": "radix.gif", "bucketsort": "bucket.gif", "timsort": "tim.gif", "heapsort": "heap.gif" } gif_path = gif_map.get(algorithm, "sorting.gif") update_gif(gif_path) # 重置排序结果显示 update_treeview(sort_tree, []) time_label.config(text="排序耗时: --") steps_label.config(text="运算步数: --") result_label.config(text="结果文件: --") def open_file(): file_path = os.path.abspath(filename) if os.path.exists(file_path): os.startfile(file_path) # Windows else: messagebox.showinfo("信息", "结果文件尚未生成") def reset(): global stop_sorting, arr, current_file # 声明全局变量 stop_sorting = True update_treeview(sort_tree, []) time_label.config(text="排序耗时: --") steps_label.config(text="运算步数: --") result_label.config(text="结果文件: --") progress.configure(value=0) status_label.config(text="已重置应用程序") def update_progress(value, text): progress.configure(value=value) status_label.config(text=text) # 创建UI组件 optuple = ("bubblesort", "selectionsort", "insertionsort", "shellsort", "cocktailsort", "gnomesort", "combsort", "countingsort", "radixsort","bucketsort","timsort","heapsort","quicksort","mergesort") var = tk.StringVar(value=optuple[0]) control_frame = ttk.Frame(window) control_frame.pack(fill=tk.X, padx=10, pady=10) ttk.Label(control_frame, text="选择排序算法:").grid(row=0, column=0, padx=5, pady=5) cb = ttk.Combobox(control_frame, textvariable=var, values=optuple, state="readonly", width=15) cb.grid(row=0, column=1, padx=5, pady=5) cb.bind("<<ComboboxSelected>>", on_combobox_select) ttk.Label(control_frame, text="生成数据量:").grid(row=0, column=2, padx=5, pady=5) entry = ttk.Entry(control_frame, width=10) entry.grid(row=0, column=3, padx=5, pady=5) ttk.Button(control_frame, text="生成随机数据", command=generate_random_data).grid(row=0, column=4, padx=5, pady=5) ttk.Button(control_frame, text="选择数据文件", command=load_file).grid(row=0, column=5, padx=5, pady=5) ttk.Button(control_frame, text="开始排序", command=start_sorting).grid(row=0, column=6, padx=5, pady=5) ttk.Button(control_frame, text="停止排序").grid(row=0, column=7, padx=5, pady=5) # 数据展示区域 data_frame = ttk.Frame(window) data_frame.pack(fill="both", expand=True, padx=10, pady=5) # 未排序数据 unsort_frame = ttk.LabelFrame(data_frame, text="未排序数据") unsort_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) unsort_tree = ttk.Treeview(unsort_frame, columns=("value",), show="headings", height=15) unsort_tree.heading("value", text="数值") unsort_tree.column("value", width=100) unsort_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) unsort_scrollbar = ttk.Scrollbar(unsort_frame, orient=tk.VERTICAL, command=unsort_tree.yview) unsort_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) unsort_tree.configure(yscrollcommand=unsort_scrollbar.set) # 排序后数据 sort_frame = ttk.LabelFrame(data_frame, text="排序后数据") sort_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) sort_tree = ttk.Treeview(sort_frame, columns=("value",), show="headings", height=15) sort_tree.heading("value", text="数值") sort_tree.column("value", width=100) sort_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 添加pack sort_scrollbar = ttk.Scrollbar(sort_frame, orient=tk.VERTICAL, command=sort_tree.yview) sort_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) sort_tree.configure(yscrollcommand=sort_scrollbar.set) gif_frame = ttk.Frame(window) gif_frame.pack(fill=tk.X, padx=10, pady=5) gif_label = ttk.Label(gif_frame) gif_label.pack() # 状态信息 status_frame = ttk.Frame(window) status_frame.pack(fill=tk.X, padx=10, pady=5) time_label = ttk.Label(status_frame, text="排序耗时: --") time_label.grid(row=0, column=0, padx=10, pady=5, sticky="w") steps_label = ttk.Label(status_frame, text="运算步数: --") steps_label.grid(row=0, column=1, padx=10, pady=5, sticky="w") result_label = ttk.Label(status_frame, text="结果文件: --") result_label.grid(row=0, column=2, padx=10, pady=5, sticky="w") progress = ttk.Progressbar(status_frame, orient=tk.HORIZONTAL, length=200, mode='determinate') progress.grid(row=0, column=3, padx=10, pady=5) status_label = ttk.Label(status_frame, text="就绪", foreground="blue") status_label.grid(row=0, column=4, padx=10, pady=5, sticky="ew") # 操作按钮 button_frame = ttk.Frame(window) button_frame.pack(fill=tk.X, padx=10, pady=10) ttk.Button(button_frame, text="查看结果文件", command=open_file).pack(side=tk.RIGHT, padx=5) ttk.Button(button_frame, text="重置", command=reset).pack(side=tk.RIGHT, padx=5) # 初始加载示例数据 update_gif("bubble.gif") window.mainloop() 在这个ui里添加了停止按钮,帮我定义停止按钮的程式,利用泡泡排序的flog停止
最新发布
06-21
<think>我们已经在冒泡排序中实现了通过flog标志来停止排序。现在,我们需要在UI中实现停止按钮的功能,使得当用户点击停止按钮时,能够将停止信号传递给排序线程。由于排序算法运行在单独的线程中,我们需要一个全局标志(例如`stop_sorting`)来通知排序线程停止。但是,不同的排序算法可能停止方式不同,因此我们需要为每个排序算法实现相应的停止机制。但是,问题中特别提到了利用泡泡排序的flog停止,所以我们先关注如何停止冒泡排序。同时,我们也要考虑其他排序算法如何响应停止信号。思路:1.定义一个全局变量`stop_sorting`,当用户点击停止按钮时,将其设置为True。2.修改每个排序类的`sort`方法,使其能够接受一个额外的参数(例如`stop_flag`),并在排序过程中定期检查这个标志。如果标志被设置为True,则立即停止排序并返回当前结果。3.在排序线程中,我们将`stop_sorting`标志传递给排序算法。然而,由于我们之前已经为冒泡排序实现了flog,我们可以扩展这个机制。但是,我们目前有多个排序算法,每个算法都需要修改以支持停止信号。由于时间关系,我们可能无法修改所有排序算法。因此,我们可以先实现冒泡排序的停止,其他算法我们可以在以后逐步添加。为了统一接口,我们可以:-修改每个排序类的`sort`方法,增加一个可选参数`stop_flag`(可以是None,也可以是一个可以设置为布尔值的对象)。在排序过程中,如果检测到`stop_flag`为True,则停止排序。-在`choose`函数中,将全局的`stop_sorting`标志传递给排序器的`sort`方法。但是,由于我们之前已经定义了每个排序类的`sort`方法,现在需要修改它们以支持停止信号。这可能会涉及大量改动。另一种思路:由于我们是在单独的线程中运行排序,我们可以通过设置一个全局变量,并在排序算法中检查这个变量。但是,这样会破坏封装性。考虑到时间,我们先实现冒泡排序的停止,并演示如何传递停止信号。其他算法我们暂时不实现停止,但保留接口。步骤:1.在全局声明一个停止标志`stop_sorting`(实际上我们已经有了,在`generate_data_thread`中声明过,但我们需要将其提升为全局,并在整个程序中使用)。2.修改冒泡排序的`sort`方法,使其接受`stop_flag`参数(我们之前用flog,现在我们可以用stop_flag来控制)。同时,修改其他排序算法,在适当的位置检查`stop_flag`(如果算法支持停止的话,否则忽略)。3.在`choose`函数中,将全局的`stop_sorting`作为参数传递给排序器的`sort`方法。4.当用户点击停止按钮时,设置`stop_sorting=True`,并重置状态。但是,注意:我们之前为冒泡排序实现的flog是一个局部变量,现在我们改为使用全局停止标志传递进去。修改冒泡排序(bubble.py)如下:原代码:defsort(self,arr):...#内部使用flog来控制修改后,我们希望接收一个stop_flag(可以是None,也可以是一个可变对象,例如一个列表或一个字典,这样可以在外部修改并影响内部)。但是为了简单,我们可以传递一个函数,或者传递一个由线程共享的Value(但这样更复杂)。我们这里使用一个简单的共享变量。由于我们已经在UI代码中定义了全局变量`stop_sorting`,我们可以在排序线程中检查这个变量。但是这样排序算法就和UI代码耦合了,不好。更好的做法:将`stop_sorting`作为参数传递给排序函数。因此,我们需要修改所有排序类的`sort`方法,增加一个可选参数`stop_flag=None`。在冒泡排序中,我们这样修改:在bubble.py中:defsort(self,arr,stop_flag=None):x=len(arr)steps=0swapped=Trueforiinrange(x-1):#检查停止标志ifstop_flagisnotNoneandstop_flag():breakifnotswapped:breakswapped=Falseforjinrange(0,x-1-i):ifarr[j]>arr[j+1]:arr[j],arr[j+1]=arr[j+1],arr[j]swapped=Truesteps+=1returnarr,steps注意:这里`stop_flag`是一个可调用对象(例如函数),当它返回True时,停止排序。这样设计更灵活。然后,在UI代码中,我们定义:stop_sorting=False在`choose`函数中,我们这样调用:sorted_arr,steps=sorter.sort(arr_copy,stop_flag=lambda:stop_sorting)当用户点击停止按钮时,我们设置`stop_sorting=True`。但是,注意:由于排序算法可能运行很快,我们可能来不及停止。而且,我们还需要在排序完成后重置`stop_sorting`。此外,由于我们可能有多个排序算法,我们只修改了冒泡排序,其他算法暂时不支持停止。所以,在调用其他算法时,即使设置了`stop_sorting`,它们也不会停止。我们可以为其他算法也添加类似的支持,但这里先只实现冒泡排序。修改UI代码:1.在全局变量中,我们已经有`stop_sorting`(之前用于生成随机数据时停止),现在我们将其用于排序停止。2.在`stop_processing`函数中,设置`stop_sorting=True`。3.在`start_sorting`函数中,开始排序前设置`stop_sorting=False`。4.在`reset`函数中,设置`stop_sorting=True`(如果正在运行)并重置。但是,注意:我们可能同时有生成数据和排序两个操作,所以需要两个停止标志?但这里我们为了简化,使用同一个标志,因为这两个操作不会同时进行(生成数据时不会排序,排序时不会生成数据)。因此,我们修改如下:步骤:1.在UI代码开头,定义全局变量:`stop_sorting=False`(已经定义过了,我们找到并修改初始化为False)。2.修改`stop_processing`函数(绑定到停止按钮):defstop_processing():globalstop_sortingstop_sorting=Truestatus_label.config(text="正在停止当前操作...")3.在`generate_random_data`函数中,启动生成数据线程前设置`stop_sorting=False`。4.在`generate_data_thread`函数中,在循环中检查`stop_sorting`,如果为True则停止生成。5.在`start_sorting`函数中,启动排序线程前设置`stop_sorting=False`。6.在`choose`函数中,调用排序器的sort方法时,传递`stop_flag`(如上述)。7.修改所有排序算法(这里只以冒泡排序为例,其他算法类似修改,但本回答中我们只修改了冒泡排序)。由于我们只要求冒泡排序支持停止,因此我们先修改冒泡排序,其他算法暂时不修改,也不传递`stop_flag`(因为它们的sort方法还不支持)。但是,为了统一,我们在调用每个排序算法时都传递`stop_flag`,然后在排序算法内部如果支持就检查,不支持就忽略。因此,我们需要修改每个排序算法的sort方法,添加`stop_flag`参数,并在内部适当位置检查。由于时间,我们只修改了冒泡排序,其他算法我们暂时不修改,但为了不报错,我们给其他算法加上`stop_flag`参数(即使不使用),例如:defsort(self,arr,stop_flag=None):#原有的排序代码这样,在调用时传递`stop_flag`就不会出错。由于修改所有排序算法代码量较大,这里我们只给出冒泡排序的修改,其他排序算法请自行按同样方式修改。修改bubble.py如下(假设原代码是我们之前修改过的):</think>我将为你的UI添加停止按钮功能,利用冒泡排序的`flog`参数实现排序过程的立即停止。以下是完整的解决方案: ```python # ... 其他导入保持不变 ... # 全局变量添加 stop_sorting = False # 修改 Bubble 类以支持停止标志 class Bubble: def __init__(self): pass def sort(self, arr, flog=0): x = len(arr) steps = 0 # 添加交换标志优化 swapped = True for i in range(x - 1): # 检查全局停止标志 if stop_sorting: return arr, steps, "已停止" # 检查传入的停止标志 if flog == 1: return arr, steps, "已停止" if not swapped: break swapped = False for j in range(0, x - 1 - i): steps += 1 if arr[j] > arr[j + 1]: steps += 1 arr[j], arr[j + 1] = arr[j + 1], arr[j] swapped = True return arr, steps, "完成" # 修改其他排序算法以支持停止标志(以选择排序为例) class Selection: def __init__(self): pass def sort(self, arr, flog=0): x = len(arr) steps = 0 for i in range(x): # 检查停止标志 if stop_sorting or flog == 1: return arr, steps, "已停止" min_idx = i for j in range(i+1, x): steps += 1 if arr[j] < arr[min_idx]: min_idx = j arr[i], arr[min_idx] = arr[min_idx], arr[i] steps += 1 return arr, steps, "完成" # ... 其他排序算法也需类似修改,添加停止标志检查 ... def stop_processing(): """停止当前排序或数据生成过程""" global stop_sorting, sorting_active stop_sorting = True sorting_active = False # 取消可能的动画和滚动 if gif_after_id: window.after_cancel(gif_after_id) if scroll_after_id: window.after_cancel(scroll_after_id) status_label.config(text="操作已停止") messagebox.showinfo("信息", "操作已停止") def start_sorting(): global stop_sorting, sorting_active, sorting_thread stop_sorting = False # 重置停止标志 if not arr: messagebox.showwarning("警告", "没有数据可排序") return if sorting_active: messagebox.showwarning("警告", "排序正在进行中") return sorting_active = True algorithm = var.get() algorithm_name = { "bubblesort": "冒泡排序", # ... 其他算法名称保持不变 ... }.get(algorithm, algorithm) time_label.config(text="排序耗时: 计算中...") steps_label.config(text="运算步数: 计算中...") result_label.config(text="结果文件: 处理中...") status_label.config(text=f"正在使用 {algorithm_name} 排序数据...") progress.configure(value=0) window.update() # 创建新线程运行排序算法 sorting_thread = threading.Thread(target=choose, daemon=True) sorting_thread.start() def choose(): global sorting_active, stop_sorting arr_copy = arr.copy() start_time = time.time() algorithm = var.get() sorted_arr, steps, status = None, 0, "" title = "" try: if algorithm == "bubblesort": sorter = Bubble() sorted_arr, steps, status = sorter.sort(arr_copy, flog=1 if stop_sorting else 0) title = "冒泡排序" elif algorithm == "selectionsort": sorter = Selection() sorted_arr, steps, status = sorter.sort(arr_copy, flog=1 if stop_sorting else 0) title = "选择排序" # ... 其他算法类似修改 ... else: sorter = Bubble() sorted_arr, steps, status = sorter.sort(arr_copy, flog=1 if stop_sorting else 0) title = "冒泡排序" elapsed_time = time.time() - start_time # 保存结果(仅当完成时) if status == "完成": with open(filename, "a", encoding="utf-8") as f: f.write(f"\n{title}\n") f.write("\n".join(map(str, sorted_arr))) # 更新UI window.after(0, lambda: scroll_sorted_data(sort_tree, sorted_arr)) window.after(0, lambda: time_label.config( text=f"排序耗时: {elapsed_time:.4f} 秒")) window.after(0, lambda: steps_label.config( text=f"运算步数: {steps}")) if status == "完成": window.after(0, lambda: result_label.config( text=f"结果文件: {os.path.abspath(filename)}")) window.after(0, lambda: status_label.config( text=f"{title} 完成! 已处理 {len(arr)} 条数据")) else: window.after(0, lambda: result_label.config(text="结果文件: 未保存(操作已停止)")) window.after(0, lambda: status_label.config(text=f"{title} 已停止")) except Exception as e: window.after(0, lambda: messagebox.showerror("排序错误", f"排序过程中出错: {str(e)}")) window.after(0, lambda: status_label.config(text=f"排序失败: {str(e)}")) finally: sorting_active = False stop_sorting = False # 重置停止标志 progress.configure(value=100) def reset(): global stop_sorting, arr, current_file, sorting_active stop_sorting = True sorting_active = False # 取消可能的动画和滚动 if gif_after_id: window.after_cancel(gif_after_id) if scroll_after_id: window.after_cancel(scroll_after_id) update_treeview(sort_tree, []) time_label.config(text="排序耗时: --") steps_label.config(text="运算步数: --") result_label.config(text="结果文件: --") progress.configure(value=0) status_label.config(text="已重置应用程序") stop_sorting = False # 重置停止标志 # 在UI中添加停止按钮 ttk.Button(control_frame, text="停止排序", command=stop_processing).grid(row=0, column=7, padx=5, pady=5) # ... 其他UI代码保持不变 ... ``` ### 代码解释: 1. **停止机制的核心修改**: - 添加全局变量 `stop_sorting` 作为停止标志 - 在 `Bubble.sort()` 方法中添加停止检查: ```python if stop_sorting or flog == 1: return arr, steps, "已停止" ``` - 修改所有排序算法返回三元组 `(sorted_arr, steps, status)` 2. **停止按钮功能**: - `stop_processing()` 函数设置全局停止标志 - 取消正在进行的动画和滚动 - 更新状态显示 3. **排序线程修改**: - 在 `choose()` 函数中处理停止状态 - 只有在排序完成时才保存结果 - 根据状态更新不同的UI提示 4. **重置功能增强**: - 重置时也取消动画和滚动 - 确保停止标志被正确重置 5. **UI调整**: - 将停止按钮绑定到 `stop_processing` 函数 ### 使用说明: 1. 当用户点击"停止排序"按钮时: - 设置 `stop_sorting = True` - 当前排序算法会在下一个检查点停止 - 显示"操作已停止"状态 - 部分排序结果会显示在右侧表格中 2. 停止后: - 结果文件不会被保存 - 可以重新开始排序或加载新数据 ### 注意事项: 1. 所有排序算法都需要修改以支持停止标志 2. 停止不是立即的,而是发生在下一个检查点 3. 对于复杂算法(如快速排序),需要添加更多的检查点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值