import tkinter as tk
from tkinter import * # 导入GUI库的基础模块
from tkinter import ttk,filedialog,messagebox # 导入更漂亮的控件样式
from bubble import Bubble # 自定义的冒泡排序类
from selection import Selection
from insertion import Insertion
from shellsort import Shell
import pandas as pd # 数据处理库,用于读取CSV
import time # 计时功能
import os # 操作系统功能,用于获取文件路径
import random
from PIL import Image, ImageTk, ImageSequence
import threading
window = Tk()
window.title("排序方法")
window.geometry("1200x800+300+100") # 设置窗口大小和位置(宽x高+X坐标+Y坐标)
current_file = ""
arr = []
filename ="sort.csv"
BATCH_SIZE = 10000
gif_frame = []
gif_index = 0
gif_speed = 200
gif_after = None
gif_label = None
# 全局变量
def load_gif(file_path,size=(400,300)):
global gif_frame,gif_index
gif_frame =[]
img = Image.open(file_path)
for frame in ImageSequence.Iterator(img):
resized = frame.copy().resize(size, Image.Resampling.BILINEAR)
gif_frame.append(ImageTk.PhotoImage(resized))
gif_index = 0
return bool(gif_frame)
def open_gif():
global gif_index,gif_after
if gif_frame:
gif_label.config(image=gif_frame[gif_index])
gif_index = (gif_index + 1) % len(gif_frame)
gif_after = window.after(gif_speed,open_gif)
def update_gif(file_path):
global gif_after, gif_frame, gif_index
if gif_after:
window.after_cancel(gif_after)
if load_gif(file_path, size=(500, 300)):
open_gif()
else:
gif_label.config(text=f"GIF 加载失败: {file_path}")
def load_data(file_path):
# 加载CSV文件数据
global arr, current_file
# global 全局变量用的函式,不然改不了
chunks = []
total_size = os.path.getsize(file_path)
processed = 0
for chunk in pd.read_csv(file_path, chunksize=2000):
chunks.append(chunk)
processed += chunk.memory_usage(index=True, deep=True).sum()
progress_value = min(processed / total_size * 100, 100)
if os.path.exists(file_path):
df = pd.concat(chunks)
arr = df.values.flatten().tolist()
current_file = os.path.basename(file_path)
update_treeview(unsort_tree, arr)
update_treeview(sort_tree, [])
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],))
if end_idx < total:
# 使用计时器安排下一批处理
treeview.after(1, add_batch, end_idx)
else:
treeview.yview_moveto(1.0)
def generate_random_data():
global arr
try:
count = int(entry.get())
if count < 100:
messagebox.showerror("错误", "请输入100以上的数字")
return
# 清空现有数组
arr = []
# 启动线程生成数据
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)
update_treeview(unsort_tree, arr)
update_treeview(sort_tree, [])
# 保存数据
current_file = "random_data.csv"
pd.DataFrame(arr).to_csv(current_file, index=False)
def file():
file_path = filedialog.askopenfilename(
title="选择数据文件",
filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]
)
if file_path:
load_data(file_path)
def choose():
choose = var.get()
arr_copy = arr.copy()
# 创建数据副本(避免修改原始数据)
start_time = time.time()
if choose == "bubblesort":
sorter = Bubble()
# 创建冒泡排序对象
sorter_arr,steps = sorter.sort(arr_copy)
# 调用排序方法
title="冒泡排序"
elif choose == "selectionsort":
sorter = Selection()
sorter_arr,steps = sorter.sort(arr_copy)
title="选择排序"
elif choose == "shellsort":
sorter = Shell()
sorter_arr, steps = sorter.sort(arr_copy)
title = "希尔排序"
else:
sorter = Insertion()
sorter_arr,steps = sorter.sort(arr_copy)
title="插入排序"
# sorting_thread = threading.Thread(target=choose, daemon=True)
# sorting_thread.start()
elapsed_time = time.time() - start_time
filename = "sort.csv"
with open(filename,"a",encoding="utf-8") as f:
f.write(f"\n{title}\n")
f.write("\n".join(map(str,sorter_arr)))
# 将排序结果转为字符串并用换行符连接
label1["text"] = f"排序耗时: {elapsed_time:4f} 秒"
label2["text"] = f"运算步数: {steps}"
label3["text"] = f"结果保存至:\n{os.path.abspath(filename)}"
update_treeview(sort_tree, sorter_arr)
def open_file(event=None):
"""打开文件所在的文件夹"""
file_path = os.path.abspath(filename)
if file_path and os.path.exists(file_path):
os.startfile(file_path)
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, [])
label1.config(text="排序耗时:")
label2.config(text="运算步数:")
label3.config(text="结果文件:")
optuple = ("bubblesort","selectionsort","insertionsort","shellsort","cocktailsort","gnomesort","combsort",
"countingsort","radixsort")
var = 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=file).grid(row=0, column=5, padx=5, pady=5)
ttk.Button(control_frame,text="打开结果文件",command=open_file).grid(row=0,column=6,padx=5,pady=5)
ttk.Button(control_frame, text="开始排序",command=choose).grid(row=0, column=7, padx=5, pady=5)
ttk.Button(control_frame, text="停止排序").grid(row=0, column=8, 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)
label1 = ttk.Label(status_frame, text="排序耗时:")
label1.grid(row=0, column=0, padx=10, pady=5, sticky="w")
label2 = ttk.Label(status_frame, text="运算步数:")
label2.grid(row=0, column=1, padx=10, pady=5, sticky="w")
label3 = ttk.Label(status_frame, text="结果文件:")
label3.grid(row=0, column=2, padx=10, pady=5, sticky="w")
update_gif("bubble.gif")
window.mainloop() 如何使用threading来使选择数据文件和生产数据文件的大笔资料能够排序