news 2026/4/23 11:28:15

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于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); } } } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 23:09:03

学生认证通道开启:免费获取LobeChat高级功能

学生认证通道开启&#xff1a;免费获取LobeChat高级功能 在AI技术加速渗透教育、科研与日常生活的今天&#xff0c;越来越多的学生开始尝试构建自己的智能助手——不是为了炫技&#xff0c;而是真正用它来写论文、读文献、学编程、做项目。但问题也随之而来&#xff1a;主流AI平…

作者头像 李华
网站建设 2026/4/22 18:58:03

LobeChat在线测评自动评分系统

LobeChat在线测评自动评分系统 在教育数字化转型加速的今天&#xff0c;高校与在线教育平台正面临一个共同难题&#xff1a;如何高效、公平地评估成千上万学生的开放式问答或论述题作答&#xff1f;传统人工批改耗时费力&#xff0c;而简单的关键词匹配又难以捕捉语义深度。随着…

作者头像 李华
网站建设 2026/4/13 3:25:15

基于单片机的无刷直流电机调速控制设计

2系统设计方案 2.1总体设计 本文基于stm32实现一种无刷直流电机调速系统&#xff0c;主要实现对无刷直流电机的精确调速控制、工作状态显示、便于操作的人机界面等。具体如下&#xff1a; 电机驱动与调速&#xff1a;通过MCU输出6路PWM信号&#xff0c;控制6路功率MOS管组成的驱…

作者头像 李华
网站建设 2026/4/21 19:26:33

LobeChat移动端访问体验优化方案

LobeChat移动端访问体验优化方案 在移动设备占据用户上网时长超过70%的今天&#xff0c;一个AI聊天应用能否在手机上“好用”&#xff0c;几乎直接决定了它的实际价值。尽管许多大模型前端界面设计精美、功能丰富&#xff0c;但一旦进入手机浏览器&#xff0c;往往暴露出生硬的…

作者头像 李华
网站建设 2026/4/17 4:16:45

Leetcode刷题日记14(131-140)

目录问题1&#xff1a;问题链接&#xff1a;问题描述&#xff1a;实例&#xff1a;代码&#xff1a;问题2&#xff1a;问题链接&#xff1a;问题描述&#xff1a;实例&#xff1a;代码&#xff1a;问题3&#xff1a;问题链接&#xff1a;问题描述&#xff1a;实例&#xff1a;问…

作者头像 李华