前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >可视化排序实践之冒泡排序

可视化排序实践之冒泡排序

作者头像
孟君
发布2019-10-10 10:49:44
5960
发布2019-10-10 10:49:44
举报

如果排序过程程序执行能结合起来,那么这个过程会更加直观。 本文给出一个冒泡排序的可视化排序实现, 效果如下图所示:

一、界面组成

界面很简单就包括两个部分:界面左侧是可视化排序部分右侧是冒泡排序的代码

二、如何实现代码和排序的视觉同步?

2.1 关键点

  • 如何在页面上表示出排序程序的运行过程。
  • 如何将排序程序的运行过程和可视化排序结合起来,保持状态一致。

2.2 解决方法

在这个例子中,我用了javax.swing.JList模拟程序的运行。

javax.swing.JList有一个setSelectedIndex的方法,能高亮显示指定的行。 通过改变selectedIndex的值,能够达到模拟冒泡排序程序执行的效果。在这个过程中,记录下两个循环的索引状态值,根据这些状态值去调整可视化排序。

三、页面展示

3.1 初始化页面

程序随机产生10个数字,然后展示在左侧的排序面板中,每个数都用绿色的矩形展示。

代码语言:javascript
复制
  private List<NumberRectangle> initialNumberRectangles() {
      List<NumberRectangle> list = new ArrayList<NumberRectangle>();
      /**
       * 随机产生10个数组
       */
      Random random = new Random();
      for (int i = 1; i <= 10; i++) {
        list.add(new NumberRectangle(i, 1, random.nextInt(15) + 1,
            Color.GREEN));
      }
      return list;
  }

冒泡程序存放在左侧的javax.swing.JList中。

代码语言:javascript
复制
  private static final String[] BUBBLE_SOURCE_CODE = {
      "public void bubbleSort(int[] data) {       ",
      "  for (int i = 0; i < data.length - 1; i++) {",
      "    for (int j = 0; j < data.length - i - 1; j++) {",
      "      if (data[j] > data[j + 1]) {          ",
      "        int temp = data[j + 1];         ",
      "        data[j + 1] = data[j];           ",
      "        data[j] = temp;             ",
      "      }                              ",
      "    }                                ",
      "  }                                  ",
      "}                                    " };

  private JList<String> codeList = new JList<String>(BUBBLE_SOURCE_CODE);

3.2 运行速度设置

点击菜单栏Set下的Speed可以设置程序执行的速度。

选择不同的速度项,其会修改Timer延迟的时间,从而达到程序速度改变的效果。

代码语言:javascript
复制
  private class SpeedAction implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      Object speed = event.getSource();
      if (speed == speedMI1) {
        speedFlag = 1;
      } else if (speed == speedMI2) {
        speedFlag = 2;
      } else if (speed == speedMI3) {
        speedFlag = 3;
      } else if (speed == speedMI4) {
        speedFlag = 4;
      } else if (speed == speedMI5) {
        speedFlag = 5;
      }

      panel.timer.setDelay(1000 - 200 * (speedFlag - 1));
    }
  }

3.3 程序开始

点击菜单栏Set下的Start选项,程序就开始运行。

3.4 程序中间运行过程

排序的主要逻辑主要写在TimeAction中,

该类主要通过java.swing.JList列表的选中的索引的改变,从而决定左侧排序面板的变化,设置不同的颜色。

代码语言:javascript
复制
  private class TimerAction implements ActionListener, Serializable {

    private static final long serialVersionUID = -8671813189049345697L;

    public void actionPerformed(ActionEvent event) {
      if (completed) {
        return;
      }

      switch (selectedIndex) {
      case 1:
        if (outerLoop < 10) {
          innerLoop = 0;
          codeList.setSelectedIndex(selectedIndex++);
        } else {
          selectedIndex = 10;
        }
        break;
      case 2:
        if (innerLoop < 10 - outerLoop - 1) {
          numbers.get(innerLoop).setColor(Color.RED);
          numbers.get(innerLoop + 1).setColor(Color.BLUE);
          codeList.setSelectedIndex(selectedIndex++);
        } else {
          outerLoop++;
          selectedIndex = 1;
        }
        break;
      case 3:
        if (numbers.get(innerLoop).getValue() > numbers.get(
            innerLoop + 1).getValue()) {
          codeList.setSelectedIndex(selectedIndex++);
        } else {
          numbers.get(innerLoop + 1).setColor(Color.GREEN);
          numbers.get(innerLoop).setColor(Color.GREEN);
          innerLoop++;
          selectedIndex = 2;
        }
        break;
      case 4:
        codeList.setSelectedIndex(selectedIndex++);
        break;
      case 5:
        codeList.setSelectedIndex(selectedIndex++);
        break;

      case 6:
        codeList.setSelectedIndex(selectedIndex);
        int tempValue1 = numbers.get(innerLoop).getValue();
        int tempValue2 = numbers.get(innerLoop + 1).getValue();
        numbers.get(innerLoop + 1).setValue(tempValue1);
        numbers.get(innerLoop).setValue(tempValue2);
        numbers.get(innerLoop + 1).setColor(Color.GREEN);
        numbers.get(innerLoop).setColor(Color.GREEN);
        selectedIndex = 2;
        innerLoop++;
        break;

      case 10:
        if (selectedIndex == 10) {
          completed = true;
          codeList.setSelectedIndex(selectedIndex);
        }
        break;
      default:
        break;
      }

      repaint();

    }
  }

3.5 排序完成页面

四、实现代码

  • BubbleSortVisualizationFrame.java
代码语言:javascript
复制
package my.visualization.sort.bubble;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;

/**
 * 
 * @author wangmengjun
 *
 */
public class BubbleSortVisualizationFrame extends JFrame {

  private static final long serialVersionUID = -6725108659717827278L;

  private Container contentPane;

  /**
   * 设置三个Menu Item,分别用于开始程序,调整运行的速度以及退出程序
   * 
   */
  private JMenuItem startMI = new JMenuItem("Start");

  private JMenu speedMenu = new JMenu("Speed");

  private JMenuItem exitMI = new JMenuItem("Exit");

  /**
   * 设定5个速度级别
   */
  private JRadioButtonMenuItem speedMI1 = new JRadioButtonMenuItem("Speed1",
      true);

  private JRadioButtonMenuItem speedMI2 = new JRadioButtonMenuItem("Speed2",
      false);

  private JRadioButtonMenuItem speedMI3 = new JRadioButtonMenuItem("Speed3",
      false);

  private JRadioButtonMenuItem speedMI4 = new JRadioButtonMenuItem("Speed4",
      false);

  private JRadioButtonMenuItem speedMI5 = new JRadioButtonMenuItem("Speed5",
      false);

  public int speedFlag = 1;
  
  /**
   * 冒泡排序可视化的Panel
   */
  private BubbleSortPanel panel;

  public BubbleSortVisualizationFrame(){
    
    setTitle("可视化排序之冒泡排序");
    setSize(700, 400);
    setResizable(false);

    JMenuBar menuBar = new JMenuBar();
    setJMenuBar(menuBar);

    JMenu setMenu = new JMenu("Set");
    
    setMenu.setMnemonic('s');

    menuBar.add(setMenu);

    setMenu.add(startMI);
    setMenu.addSeparator();

    setMenu.addSeparator();
    setMenu.add(speedMenu);
    setMenu.addSeparator();
    setMenu.add(exitMI);

    ButtonGroup group = new ButtonGroup();
    group.add(speedMI1);
    group.add(speedMI2);
    group.add(speedMI3);
    group.add(speedMI4);
    group.add(speedMI5);

    speedMenu.add(speedMI1);
    speedMenu.add(speedMI2);
    speedMenu.add(speedMI3);
    speedMenu.add(speedMI4);
    speedMenu.add(speedMI5);

    startMI.addActionListener(new StartAction());
    speedMI1.addActionListener(new SpeedAction());
    speedMI2.addActionListener(new SpeedAction());
    speedMI3.addActionListener(new SpeedAction());
    speedMI4.addActionListener(new SpeedAction());
    speedMI5.addActionListener(new SpeedAction());
    exitMI.addActionListener(new ExitAction());
    
    contentPane = getContentPane();
    
    panel = new BubbleSortPanel(this);
    contentPane.add(panel);
    startMI.setEnabled(true);
  }
  
  private class StartAction implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      startMI.setEnabled(false);
      panel.timer.start();
    }
  }
  
  private class ExitAction implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      System.exit(0);
    }
  }
  
  private class SpeedAction implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      Object speed = event.getSource();
      if (speed == speedMI1) {
        speedFlag = 1;
      } else if (speed == speedMI2) {
        speedFlag = 2;
      } else if (speed == speedMI3) {
        speedFlag = 3;
      } else if (speed == speedMI4) {
        speedFlag = 4;
      } else if (speed == speedMI5) {
        speedFlag = 5;
      }

      panel.timer.setDelay(1000 - 200 * (speedFlag - 1));
    }
  }
  
}
  • BubbleSortPanel.java
代码语言:javascript
复制
package my.visualization.sort.bubble;

/**
 * @author wangmengjun
 *
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;

public class BubbleSortPanel extends JPanel {

  private static final long serialVersionUID = -9149581857139587792L;

  private static final String[] BUBBLE_SOURCE_CODE = {
      "public void bubbleSort(int[] data) {       ",
      "  for (int i = 0; i < data.length - 1; i++) {",
      "    for (int j = 0; j < data.length - i - 1; j++) {",
      "      if (data[j] > data[j + 1]) {          ",
      "        int temp = data[j + 1];         ",
      "        data[j + 1] = data[j];           ",
      "        data[j] = temp;             ",
      "      }                              ",
      "    }                                ",
      "  }                                  ",
      "}                                    " };

  private JList<String> codeList = new JList<String>(BUBBLE_SOURCE_CODE);

  /**
   * 初始化10个数据
   */
  private List<NumberRectangle> numbers = initialNumberRectangles();

  
  public TimerAction timerAction;

  public Timer timer;

  public BubbleSortVisualizationFrame frame;

  public BubbleSortPanel(BubbleSortVisualizationFrame frame) {

    timerAction = new TimerAction();
    timer = new Timer(1000, timerAction);

    codeList.setSelectedIndex(1);
    JScrollPane scrollPane1 = new JScrollPane(codeList);
    this.setLayout(new BorderLayout());
    this.add(scrollPane1, BorderLayout.EAST);

    this.frame = frame;
  }

  /**
   * 判断排序是否已经结束
   */
  private boolean completed = false;

  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;

    drawNumberRectangles(g2);
  }

  private void drawNumberRectangles(Graphics2D g2) {
    for (NumberRectangle rectangle : numbers) {
      rectangle.draw(g2);
    }
  }

  int outerLoop = 0;
  int innerLoop = 0;
  int selectedIndex = 1;

  private class TimerAction implements ActionListener, Serializable {

    private static final long serialVersionUID = -8671813189049345697L;

    public void actionPerformed(ActionEvent event) {
      if (completed) {
        return;
      }

      switch (selectedIndex) {
      case 1:
        if (outerLoop < 10) {
          innerLoop = 0;
          codeList.setSelectedIndex(selectedIndex++);
        } else {
          selectedIndex = 10;
        }
        break;
      case 2:
        if (innerLoop < 10 - outerLoop - 1) {
          numbers.get(innerLoop).setColor(Color.RED);
          numbers.get(innerLoop + 1).setColor(Color.BLUE);
          codeList.setSelectedIndex(selectedIndex++);
        } else {
          outerLoop++;
          selectedIndex = 1;
        }
        break;
      case 3:
        if (numbers.get(innerLoop).getValue() > numbers.get(
            innerLoop + 1).getValue()) {
          codeList.setSelectedIndex(selectedIndex++);
        } else {
          numbers.get(innerLoop + 1).setColor(Color.GREEN);
          numbers.get(innerLoop).setColor(Color.GREEN);
          innerLoop++;
          selectedIndex = 2;
        }
        break;
      case 4:
        codeList.setSelectedIndex(selectedIndex++);
        break;
      case 5:
        codeList.setSelectedIndex(selectedIndex++);
        break;

      case 6:
        codeList.setSelectedIndex(selectedIndex);
        int tempValue1 = numbers.get(innerLoop).getValue();
        int tempValue2 = numbers.get(innerLoop + 1).getValue();
        numbers.get(innerLoop + 1).setValue(tempValue1);
        numbers.get(innerLoop).setValue(tempValue2);
        numbers.get(innerLoop + 1).setColor(Color.GREEN);
        numbers.get(innerLoop).setColor(Color.GREEN);
        selectedIndex = 2;
        innerLoop++;
        break;

      case 10:
        if (selectedIndex == 10) {
          completed = true;
          codeList.setSelectedIndex(selectedIndex);
        }
        break;
      default:
        break;
      }

      repaint();

    }
  }

  private List<NumberRectangle> initialNumberRectangles() {
    List<NumberRectangle> list = new ArrayList<NumberRectangle>();
    /**
     * 随机产生10个数组
     */
    Random random = new Random();
    for (int i = 1; i <= 10; i++) {
      list.add(new NumberRectangle(i, 1, random.nextInt(15) + 1,
          Color.GREEN));
    }
    return list;
  }

}
  • NumberRectangle.java
代码语言:javascript
复制
package my.visualization.sort.bubble;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;

/**
 * 
 * @author wangmengjun
 *
 */
public class NumberRectangle {

  private int x;

  private int y;

  private int value;

  private Color color;

  public NumberRectangle() {
  }

  public NumberRectangle(int x, int y, int value, Color color) {
    this.x = x;
    this.y = y;
    this.color = color;
    this.value = value;

  }

  public void draw(Graphics2D g2) {
    int clientX = 30 + x * 30;
    int clientY = 20 + y * 10;
    Rectangle2D.Double rect = new Rectangle2D.Double(clientX, clientY, 20,
        value * 20);
    g2.setPaint(color);
    g2.fill(rect);
    g2.setPaint(Color.BLACK);
    g2.draw(rect);
    g2.drawString(String.valueOf(value), clientX, clientY - 10);
  }

  /**
   * @return the color
   */
  public Color getColor() {
    return color;
  }

  /**
   * @param color
   *            the color to set
   */
  public void setColor(Color color) {
    this.color = color;
  }

  /**
   * @return the x
   */
  public int getX() {
    return x;
  }

  /**
   * @param x
   *            the x to set
   */
  public void setX(int x) {
    this.x = x;
  }

  /**
   * @return the y
   */
  public int getY() {
    return y;
  }

  /**
   * @param y
   *            the y to set
   */
  public void setY(int y) {
    this.y = y;
  }

  /**
   * @return the value
   */
  public int getValue() {
    return value;
  }

  /**
   * @param value
   *            the value to set
   */
  public void setValue(int value) {
    this.value = value;
  }

}
  • BubbleSortApplication.java
代码语言:javascript
复制
package my.visualization.sort.bubble;

import javax.swing.JFrame;

public class BubbleSortApplication {
  @SuppressWarnings("deprecation")
  public static void main(String[] args) {
    BubbleSortVisualizationFrame frame = new BubbleSortVisualizationFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.show();
  }
}

五、某次运行效果

这样,一个简单地,模拟执行结合排序变化的例子就完成了。:) 有兴趣的读者可以试一试。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟君的编程札记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、界面组成
    • 2.1 关键点
    • 三、页面展示
      • 3.1 初始化页面
        • 3.2 运行速度设置
          • 3.3 程序开始
          • 四、实现代码
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档