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

五迷三道 提交于 2020-10-28 09:11:56

如果排序过程程序执行能结合起来,那么这个过程会更加直观。 

本文给出一个冒泡排序的可视化排序实现, 效果如下图所示:

 

界面组成

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




 

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

关键点

如何在页面上表示出排序程序的运行过程。

如何将排序程序的运行过程和可视化排序结合起来,保持状态一致。 

解决方法

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

javax.swing.JList有一个setSelectedIndex的方法,能高亮显示指定的行。

通过改变selectedIndex的值,能够达到模拟冒泡排序程序执行的效果。在这个过程中,记录下两个循环的索引状态值,根据这些状态值去调整可视化排序。 
 

页面展示

 初始化页面

 

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

	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中。

	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);

 

运行速度设置

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

 

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

	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));
		}
	}

 

程序开始

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


程序中间运行过程

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

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

	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();

		}
	}

 

 



排序完成页面 

实现代码

BubbleSortVisualizationFrame.java

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

/**
 * 
 */
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

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

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();
	}
}

 

某次运行效果

这样,一个简单地,模拟执行结合排序变化的例子就完成了。 :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!