可视化查找之二分查找

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

本文简单地实现了二分查找的可视化。界面很简单就包括两个部分:界面左侧是可视化查找部分,右侧是二分查找的代码。如下图所示:

可视化查找之二分查找_第1张图片

程序的关键点主要有两点:
1. 如何在页面上表示出查找程序的运行过程。
2. 如何将排序程序的运行过程和可视化查找结合起来,保持状态一致。

我的解决方法如下:
我采用了JList去模拟程序的执行,JList有一个setSelectedIndex的方法,能高亮显示指定的行。通过改变selectedIndex的值,能够达到模拟程序执行的效果。根据模拟程序中保存的状态值去修改可视化查找。

程序主要是随机产生10个数值,查找数字9.
可视化查找之二分查找_第2张图片

可以找到的运行情况:


可视化查找之二分查找_第3张图片


可视化查找之二分查找_第4张图片


可视化查找之二分查找_第5张图片


找不到的运行情况:


可视化查找之二分查找_第6张图片


可视化查找之二分查找_第7张图片


可视化查找之二分查找_第8张图片

程序代码如下:

package my.visualization.search.binary;

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.JOptionPane;
import javax.swing.JRadioButtonMenuItem;

/**
 * 
 * @author Eric
 * @version 1.0
 *
 */
public class BinarySearchVisualizationFrame 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");
	
	private JMenuItem aboutMI = new JMenuItem("About");

	/**
	 * 设定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 BinarySearchPanel panel;

	public BinarySearchVisualizationFrame(){
		
		setTitle("可视化查找之二分查找");
		setSize(700, 400);
		setResizable(false);

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

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

		menuBar.add(setMenu);
		menuBar.add(helpMenu);

		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());
		helpMenu.add(aboutMI);
		aboutMI.addActionListener(new AboutAction());
		
		
		contentPane = getContentPane();
		
		panel = new BinarySearchPanel(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));
		}
	}
	
	private class AboutAction implements ActionListener {
		public void actionPerformed(ActionEvent event) {
			String string = "说明:\n1.本程序可视化二分查找的过程\n" + "2.查找的数字为9\n" + "3.low的颜色用PINK表示\n"
			+ "4.high的颜色用CYAN表示\n" + "5.如果能找到,找到的数字用蓝色表示\n"+"6. 如果没有找到,颜色全部为绿色";
	JOptionPane.showMessageDialog(BinarySearchVisualizationFrame.this, string);
		}
	}
	
}



package my.visualization.search.binary;

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.Arrays;
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 BinarySearchPanel extends JPanel {

	private static final long serialVersionUID = -9149581857139587792L;

	private static final String[] code = {
			"public int binarySearch0(int[] a, int key) {", 
			"   int low = 0;",
			"   int high = a.length - 1;", 
			"   while (low <= high) {",
			"     int mid = (low + high) >>> 1;     ",
			"     int midVal = a[mid];          ", 
			"     if (midVal < key)",
			"	    low = mid + 1;    ",
			"     else if (midVal > key)                           ",
			"       high = mid - 1;                                 ",
			"     else ", 
			"       return mid; ", 
			"   }",
			"   return -1", 
			"}" };

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

	private JList codeList = new JList(code);;

	public TimerAction timerAction;

	public Timer timer;

	public BinarySearchVisualizationFrame frame;

	public BinarySearchPanel(BinarySearchVisualizationFrame 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 low = 0;

	int high = 9;

	int selectedIndex = 1;

	int mid = 0;

	int key = 9;

	int midVal = 0;

	private class TimerAction implements ActionListener, Serializable {

		private static final long serialVersionUID = -8671813189049345697L;

		public void actionPerformed(ActionEvent event) {
			if (completed) {
				return;
			}
			/**
			 * 为low 和 high着色
			 */
			switch (selectedIndex) {
			case 1:
				codeList.setSelectedIndex(selectedIndex++);
				break;
			case 2:
				codeList.setSelectedIndex(selectedIndex++);
				break;
			case 3:
				numbers.get(low).setColor(Color.PINK);
				numbers.get(high).setColor(Color.CYAN);
				//while(low <high)
				codeList.setSelectedIndex(selectedIndex);
				if (low <= high) {
					selectedIndex++;
				} else {
					numbers.get(low).setColor(Color.GREEN);
					numbers.get(high).setColor(Color.GREEN);
					selectedIndex = 13;
				}
				break;
			case 4:
				codeList.setSelectedIndex(selectedIndex++);
				mid = (low + high) >>> 1;
				
				break;
			case 5:
				codeList.setSelectedIndex(selectedIndex++);
				midVal = numbers.get(mid).getValue();
				
				break;
				
			case 6 :
				codeList.setSelectedIndex(selectedIndex);
				if(midVal < key){
					selectedIndex = 7;
				}else{
					selectedIndex = 8;
				}
				break;
				
			case 7:
				codeList.setSelectedIndex(selectedIndex);
				numbers.get(low).setColor(Color.GREEN);
				low = mid+1;
				selectedIndex = 3;
				break;
			case 8:
				codeList.setSelectedIndex(selectedIndex);
				if(midVal > key){
					selectedIndex = 9;
				}else{
					selectedIndex = 10;
				}
				break;
			case 9:
				codeList.setSelectedIndex(selectedIndex);
				numbers.get(high).setColor(Color.GREEN);
				high = mid -1;
				selectedIndex = 3;
				break;
			case 10:
				codeList.setSelectedIndex(selectedIndex++);
				break;
			case 11:
				codeList.setSelectedIndex(selectedIndex);
				//mid的方格着色
				completed = true;
				numbers.get(low).setColor(Color.GREEN);
				numbers.get(high).setColor(Color.GREEN);
				numbers.get(mid).setColor(Color.BLUE);
				break;
			case 13:
				codeList.setSelectedIndex(selectedIndex);
				completed = true;
				break;
			default:
				break;
			}

			repaint();

		}
	}

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

}


package my.visualization.search.binary;

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

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

}


package my.visualization.search.binary;

import javax.swing.JFrame;

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


程序代码也没有优化过,注释也基本上没有加,不好意思。大家如果有其它好的想法,请共享一下哦。

你可能感兴趣的:(二分查找,swing,可视化)