当前位置: 首页 > news >正文

基于Java Swing的排序算法可视化器(2)

1、演示视频

基于Java Swing的排序算法可视化器

2、项目截图

设计说明

3.1 整体架构设计

本项目采用MVC(模型-视图-控制器)的设计思想进行架构划分,将数据处理、界面展示和用户交互分离,提高代码的可维护性和扩展性:

  • 模型(Model):包括数组数据、排序算法逻辑、排序状态控制(如isSorting、isPaused),负责数据的存储和处理。
  • 视图(View):基于Java Swing的GUI组件,包括窗口、控制面板、绘图面板(SortingPanel),负责界面的展示和渲染。
  • 控制器(Controller):包括按钮的事件监听器、排序线程的管理,负责处理用户的交互操作,并协调模型和视图的交互。

3.2 关键技术点设计

3.2.1 多线程设计

为了避免排序算法的执行阻塞UI线程(导致界面卡死),项目使用独立的线程执行排序逻辑:

  • 点击“开始排序”后,创建新的Thread线程执行排序算法。
  • 使用AtomicBoolean类型的变量(isSorting、isPaused)控制排序状态,保证跨线程的状态可见性和原子性。
  • 使用Object对象作为暂停锁(pauseLock),通过wait()和notify()方法实现线程的暂停和唤醒。
3.2.2 GUI渲染设计

自定义绘图面板(SortingPanel)继承自JPanel,重写paintComponent()方法实现柱状图的绘制:

  • 根据数组长度计算每个柱状图的宽度和间距,保证布局的美观性。
  • 根据当前操作的索引(currentIndex)和比较的索引(compareIndex)设置不同的颜色,实现高亮标记。
  • 使用SwingUtilities.invokeLater()方法确保UI更新操作在事件调度线程(EDT)中执行,避免线程安全问题。
3.2.3 状态管理设计

使用AtomicBoolean替代普通的volatile布尔变量,保证状态修改的原子性:

  • isSorting:标记是否正在排序,控制开始按钮的启用/禁用。
  • isPaused:标记是否暂停排序,控制暂停/继续按钮的启用/禁用。
  • isNormalComplete:使用AtomicBoolean包装,标记是否正常完成排序,避免Lambda表达式引用局部变量的编译错误。

四、算法说明

本项目支持7种常见的排序算法,以下是各算法的核心原理、时间复杂度和特点说明:

排序算法核心原理平均时间复杂度最好时间复杂度最坏时间复杂度空间复杂度稳定性
冒泡排序相邻元素两两比较,将较大的元素逐步“冒泡”到数组末尾O(n²)O(n)O(n²)O(1)稳定
选择排序每次选择未排序部分的最小元素,放到已排序部分的末尾O(n²)O(n²)O(n²)O(1)不稳定
插入排序将当前元素插入到已排序部分的合适位置,类似整理扑克牌O(n²)O(n)O(n²)O(1)稳定
快速排序选择基准元素,将数组分为小于基准和大于基准的两部分,递归排序O(n log n)O(n log n)O(n²)O(log n)不稳定
归并排序将数组分成两部分递归排序,然后合并两个有序的子数组O(n log n)O(n log n)O(n log n)O(n)稳定
希尔排序插入排序的改进版,按步长分组进行插入排序,逐步减小步长O(n log n)O(n log² n)O(n log² n)O(1)不稳定
堆排序构建大顶堆,将堆顶元素与末尾元素交换,重新堆化,重复操作O(n log n)O(n log n)O(n log n)O(1)不稳定

4.1 算法实现共性

所有排序算法的实现都加入了以下共性逻辑,以支持可视化和交互功能:

  • 在关键步骤调用checkPause()方法,检查是否需要暂停排序。
  • 设置currentIndex和compareIndex标记当前操作和比较的元素,用于界面高亮。
  • 调用SwingUtilities.invokeLater()刷新绘图面板,展示最新的排序状态。
  • 添加Thread.sleep()方法控制排序速度,让用户能够清晰看到每一步的过程。

五、测试说明

5.1 测试环境

  • 操作系统:Windows 10/11、macOS、Linux(兼容所有支持Java的系统)
  • JDK版本:JDK 8及以上
  • 开发工具:IntelliJ IDEA、Eclipse(可选)

5.2 测试用例

测试用例编号测试内容测试步骤预期结果
TC001随机数组生成1. 启动程序;2. 点击“生成随机数组”按钮界面展示新的随机柱状图,无报错
TC002排序算法执行1. 选择“冒泡排序”;2. 点击“开始排序”柱状图动态排序,最终有序,弹出耗时提示
TC003暂停功能1. 开始排序;2. 点击“暂停”按钮排序停止,弹出暂停提示,暂停按钮禁用,继续按钮启用
TC004继续功能1. 暂停排序;2. 点击“继续”按钮排序恢复执行,继续按钮禁用,暂停按钮启用
TC005重置功能(排序中)1. 开始排序;2. 点击“重置”按钮排序中断,数组重置为随机状态,无排序完成提示
TC006重置功能(排序完成)1. 排序完成;2. 点击“重置”按钮数组重置为随机状态,按钮恢复初始状态
TC007算法切换测试1. 选择“快速排序”;2. 开始排序;3. 完成后选择“堆排序”;4. 开始排序不同算法均能正常执行,展示对应的排序过程

5.3 测试注意事项

  • 测试时需确保JDK版本为8及以上,避免语法兼容问题。
  • 排序过程中频繁点击暂停/继续/重置按钮,测试线程安全和状态管理的稳定性。
  • 测试不同的数组长度(修改arraySize变量),确保绘图面板的适配性。

六、关键代码

6.1 自定义绘图面板(SortingPanel)

负责柱状图的绘制和颜色高亮标记,是可视化的核心组件:

private class SortingPanel extends JPanel { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (array == null) { return; } int barWidth = PANEL_WIDTH / arraySize; int gap = 2; int drawableWidth = barWidth - gap; for (int i = 0; i < arraySize; i++) { int barHeight = array[i]; int x = i * barWidth + gap / 2; int y = PANEL_HEIGHT - barHeight; // 设置柱形颜色 setBarColor(g, i); // 绘制柱形 g.fillRect(x, y, drawableWidth, barHeight); g.setColor(Color.BLACK); g.drawRect(x, y, drawableWidth, barHeight); } } /** * 设置柱形颜色 */ private void setBarColor(Graphics g, int index) { if (index == currentIndex) { g.setColor(Color.RED); // 操作中元素标红 } else if (index == compareIndex) { g.setColor(Color.ORANGE); // 比较中元素标橙 } else { g.setColor(Color.BLUE); // 普通元素标蓝 } } }

6.2 暂停检查方法(checkPause)

实现排序线程的暂停和唤醒,是交互功能的核心逻辑:

/** * 暂停检查:在排序步骤中调用,若暂停则等待被唤醒 * @throws InterruptedException 线程中断异常 */ private void checkPause() throws InterruptedException { synchronized (pauseLock) { while (isPaused.get() && !Thread.currentThread().isInterrupted()) { pauseLock.wait(); // 暂停线程,直到被notify } } // 若线程被中断,抛出异常终止排序 if (Thread.currentThread().isInterrupted()) { throw new InterruptedException("排序被重置中断"); } }

6.3 开始排序的事件监听器(StartSortListener)

处理开始排序的用户操作,管理排序线程的创建和执行:

private class StartSortListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (isSorting.get()) { JOptionPane.showMessageDialog(null, "正在排序中,请等待!", "提示", JOptionPane.INFORMATION_MESSAGE); return; } // 修复:将变量声明为final,确保Lambda可以引用 final String selectedAlgorithm = (String) algorithmComboBox.getSelectedItem(); // 修复:使用AtomicBoolean包装isNormalComplete,使其引用为final,值可修改 final AtomicBoolean isNormalComplete = new AtomicBoolean(true); // 开启新线程执行排序 sortingThread = new Thread(() -> { // 设置排序状态为true isSorting.set(true); isPaused.set(false); // 强制在UI线程更新按钮状态(关键:排序线程启动后立即刷新) SwingUtilities.invokeLater(() -> { updateButtonStates(); sortingPanel.repaint(); }); long startTime = System.currentTimeMillis(); try { // 执行选中的排序算法 switch (selectedAlgorithm) { case "冒泡排序": bubbleSort(); break; case "选择排序": selectionSort(); break; case "插入排序": insertionSort(); break; case "快速排序": quickSort(0, arraySize - 1); break; case "归并排序": mergeSort(); break; case "希尔排序": shellSort(); break; case "堆排序": heapSort(); break; default: JOptionPane.showMessageDialog(null, "暂不支持该算法!", "错误", JOptionPane.ERROR_MESSAGE); isNormalComplete.set(false); // 非算法执行,标记为非正常完成 break; } } catch (InterruptedException ex) { // 捕获中断异常(重置时触发):标记为非正常完成 isNormalComplete.set(false); Thread.currentThread().interrupt(); // 保留中断状态 System.out.println("排序被重置中断:" + ex.getMessage()); } // 排序完成/中断后的处理:重置状态 isSorting.set(false); isPaused.set(false); sortingThread = null; resetHighlightIndex(); // 更新GUI(强制在UI线程执行) SwingUtilities.invokeLater(() -> { // 仅当正常完成时,才显示排序完成提示(核心修复:用AtomicBoolean的get方法判断) if (isNormalComplete.get()) { long endTime = System.currentTimeMillis(); JOptionPane.showMessageDialog(null, selectedAlgorithm + "完成!\n耗时:" + (endTime - startTime) + "ms", "排序完成", JOptionPane.INFORMATION_MESSAGE); } sortingPanel.repaint(); updateButtonStates(); }); }); // 启动线程 sortingThread.start(); } }

6.4 冒泡排序实现(含可视化和暂停逻辑)

所有排序算法的实现模板,包含暂停检查、高亮标记和界面刷新:

/** * 冒泡排序(添加暂停检查) */ private void bubbleSort() throws InterruptedException { int n = array.length; for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { checkPause(); currentIndex = j; compareIndex = j + 1; SwingUtilities.invokeLater(() -> sortingPanel.repaint()); Thread.sleep(30); if (array[j] > array[j + 1]) { swap(j, j + 1); SwingUtilities.invokeLater(() -> sortingPanel.repaint()); Thread.sleep(30); } } } }
http://www.jsqmd.com/news/101800/

相关文章:

  • 科研绘图中的色卡选择与高级 Colorbar 设计
  • 基于Java Swing的排序算法可视化器(1)
  • 大语言模型(LLM)学习秘籍:从初学者到专家的必经之路,数学基础与工程实战全解析!
  • RAG聊天机器人终极优化指南
  • Git撤销修改:git restore . 与 git reset --hard 万字详解
  • LobeChat + GPU算力 高效私有化部署AI聊天系统
  • 电子邮件营销模板:LobeChat编写个性化正文
  • mybatis-动态sql语句-<foreach>
  • Leetcode刷题日记15(141-150)
  • LobeChat文件上传功能详解:图文混合输入不再是难题
  • Leetcode刷题日记16(151-160)
  • 本周GitHub九大神级项目推荐,轻松入门大模型技术,错过就是遗憾!
  • Leetcode刷题日记17(161-170)
  • TensorFlow调试报错看不懂?LobeChat帮你解读
  • Leetcode刷题日记18(171-180)
  • LobeChat研究方向建议生成AI
  • 基于PLC控制的四路抢答器设计
  • 【Java SE 基础学习打卡】25 循环结构 - for
  • 2025年度最佳远控软件评选:十佳品牌出炉,国产软件居多!
  • 自动化测试:Java+Selenium自动化测试环境搭建
  • LobeChat百度收录加速方法
  • 软件测试基础知识最强总结
  • python爬虫学习(搜索)
  • DownKyi终极指南:5步掌握B站视频批量下载技巧
  • python的fastapi+uvicorn的linux离线部署
  • 9、循环迭代与函数构建:脚本编程的核心技巧
  • LobeChat与IPFS结合实现去中心化聊天存档
  • LobeChat镜像部署指南:快速搭建属于你的开源ChatGPT聊天界面
  • Jmeter+Jenkins接口压力测试持续集成
  • 从 JavaScript 到 Python:前端工程师的完全转换指南