Java GUI : 实现排序算法的动态演示

0.用到的jar包

jcommon-1.0.16.jar、jfreechart-1.0.13.jar

1.实现思路

自定义一个类---用于存放排序算法的操作状态--SortEntity

定义一个方法类---定义一个List<SortEntity>,存放当前排序的算法所有的时刻的状态值---SortUtils

定义一个工具类---传入一个SortEntity,根据SortEntity构建一个JPanel

在UI中通过线程来循环遍历List<SortEntity>,实现动画

3.SortEntity的定义

package com.edusys.utils;

import java.util.Arrays;

public class SortEntity {
    public int[] dataList=new int[20];
    public int index_i;
    public int index_j;
    public int pivot=0;
    
    public int[] getDataList() {
        return dataList;
    }
    public void setDataList(int[] dataList) {
        for(int i=0;i<dataList.length;i++){
            this.dataList[i] = dataList[i];
        }
    }
    public int getIndex_i() {
        return index_i;
    }
    public void setIndex_i(int index_i) {
        this.index_i = index_i;
    }
    public int getIndex_j() {
        return index_j;
    }
    public void setIndex_j(int index_j) {
        this.index_j = index_j;
    }
    public int getPivot() {
        return pivot;
    }
    public void setPivot(int pivot) {
        this.pivot = pivot;
    }
    
    public SortEntity() {
    }
    public SortEntity(int[] dataList, int index_i, int index_j, int pivot) {
        for(int i=0;i<dataList.length;i++){
            this.dataList[i] = dataList[i];
        }
        this.index_i = index_i;
        this.index_j = index_j;
        this.pivot = pivot;
    }
    
    @Override
    public String toString() {
        return "SortEntity [dataList=" + Arrays.toString(dataList) + ", index_i=" + index_i + ", index_j=" + index_j
                + ", pivot=" + pivot + "]";
    }
    
}

PS:这里填个坑,数组赋值时不能直接赋值,必须进行拷贝

this.dataList=dataList;
替换为:
for(int i=0;i<dataList.length;i++){
    this.dataList[i] = dataList[i];
}

否则拷贝出的只是一个长度为传入长度的有序数组:[1,2,3,4,5......]

4.SortUtils的定义

package com.edusys.utils;

import java.util.ArrayList;
import java.util.List;

public class SortUtils {
    private static int length=20;
    private int[] dataList;
    private List<SortEntity> quickList=new ArrayList<SortEntity>();;
    private List<SortEntity> bubbleList=new ArrayList<SortEntity>();;
    private List<SortEntity> shellList=new ArrayList<SortEntity>();;
    
    public int[] getDataList() {
        return dataList;
    }
    
    public void setDataList() {
        dataList = new int[length];
        
        boolean flag=false;
        int temp;
        int index = 0;
        while(index < length){
            temp = (int)(Math.random()*length)+1;
            //Check the same element
            for(int j=0;j<index;j++){
                if(temp == dataList[j]){
                    flag=true;
                    break;
                }
                else{
                    flag = false;
                }
            }
            if(!flag ){
                dataList[index++] = temp;
            }
        }
    }

    /**
     * 对初始数组进行赋值
     */
    public SortUtils(){
        setDataList();
    }
    /**
     * 得到快速排序的结果集
     * @return
     */
    public List<SortEntity> getQuickList(){
        quickSort(getDataList(),0,length-1);
        return quickList;
    }
    
    /**
     * 得到冒泡排序结果集
     * @return
     */
    public List<SortEntity> getBubbleList() {
        bubbleList.add(new SortEntity(getDataList(), 0, 1, 0));
        bubbleSort(getDataList());
        
        return bubbleList;
    }
    
    /**
     * 得到希尔排序的结果集
     * @return
     */
    public List<SortEntity> getShellList() {
        shellList.add(new SortEntity(getDataList(), 0, 1, 0));
        shellSort(getDataList());
        return shellList;
    }
    
    /**
     * 快速排序
     * @param a
     * @param left
     * @param right
     */
    public void quickSort(int[] arr,int left,int right) {
        if(left>right){
            return; 
        }
        int pivot=arr[left];
        quickList.add(new SortEntity(arr, left, right, pivot));
        
        //定义基准值为数组第一个数 
        int i=left; 
        int j=right; 
        while(i<j) {
            //从右往左找比基准值小的数 
            while(pivot<=arr[j]&&i<j){
                j--; 
                quickList.add(new SortEntity(arr, left, right, pivot));
            }
            //从左往右找比基准值大的数
            while(pivot>=arr[i]&&i<j){
                i++;
                quickList.add(new SortEntity(arr, left, right, pivot));
            }
            //如果i<j,交换它们
            if(i<j){
                int temp=arr[i];
                arr[i]=arr[j]; 
                arr[j]=temp;
                quickList.add(new SortEntity(arr, left, right, pivot));
            } 
        } 
        //把基准值放到合适的位置 
        arr[left]=arr[i];
        arr[i]=pivot;
        //对左边的子数组进行快速排序 
        quickSort(arr,left,i-1);
        //对右边的子数组进行快速排序 
        quickSort(arr,i+1,right);
    }
    /**
     * 冒泡排序
     * @param arr
     */
    public void bubbleSort(int[] arr){
        for(int i=0;i<arr.length-1;i++){//外层循环控制排序趟数
            for(int j=0;j<arr.length-1-i;j++){//内层循环控制每一趟排序多少次
                if(arr[j]>arr[j+1]){
                    int temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
                bubbleList.add(new SortEntity(arr, i, j, 0));
            } 
        }
    }
    /**
     * 希尔排序
     * @param arr
     */
    public void shellSort(int[] arr){
        //增量
        int incrementNum = arr.length/2;
        while(incrementNum >=1){
            for(int i=0;i<arr.length;i++){
                //进行插入排序
                for(int j=i;j<arr.length-incrementNum;j=j+incrementNum){
                    if(arr[j]>arr[j+incrementNum]){
                        int temple = arr[j];
                        arr[j] = arr[j+incrementNum];
                        arr[j+incrementNum] = temple;
                    }
                    shellList.add(new SortEntity(arr, i, j, 0));
                }
            }
            //设置新的增量
            incrementNum = incrementNum/2;
        }
    }
}

此方法可以定义多个List<SortEntity>,实现各种不同的算法排序

5.HistogramUtils的实现

package com.edusys.utils;

import java.awt.Font;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.CategoryTextAnnotation;
import org.jfree.chart.axis.CategoryAnchor;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.TextAnchor;

public class HistogramUtils {
    
    private SortEntity sortEntity;

    public HistogramUtils(SortEntity sortEntity) {
        this.sortEntity=sortEntity;
    }
     /**
     * 创建柱状图数据集
     * @return
     */
    public CategoryDataset createDataset(){ 
        DefaultCategoryDataset dataset=new DefaultCategoryDataset();
        int[] dataList=sortEntity.getDataList();
        for(int i=0;i<dataList.length;i++){
            if(sortEntity.getIndex_i()==i){
                dataset.setValue(sortEntity.getDataList()[i],"", sortEntity.getDataList()[i]+"  i");
            }else if(sortEntity.getIndex_j()==i){
                dataset.setValue(sortEntity.getDataList()[i],"", sortEntity.getDataList()[i]+"  j");
            }else{
                dataset.setValue(sortEntity.getDataList()[i],"", sortEntity.getDataList()[i]+"");
            }
        }
  
        return dataset;
    }
    /**
     * 用数据集创建一个图表
     * @param dataset
     * @return
     */
    public JFreeChart createChart(CategoryDataset dataset){ 
        JFreeChart chart=ChartFactory.createBarChart("", "","", dataset, PlotOrientation.VERTICAL, true, true, false); //创建一个JFreeChart
        chart.setTitle(new TextTitle("",new Font("宋体",Font.BOLD+Font.ITALIC,40)));//可以重新设置标题,替换“hi”标题
        CategoryPlot plot=(CategoryPlot)chart.getPlot();//获得图标中间部分,即plot
        CategoryAxis categoryAxis=plot.getDomainAxis();//获得横坐标
        categoryAxis.setLabelFont(new Font("微软雅黑",Font.BOLD,10));//设置横坐标字体
        categoryAxis.setMaximumCategoryLabelWidthRatio(2f);
        categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_90);
        return chart;
    }
    /**
     * 生成一个Jpanel
     * @return
     */
    public JPanel createPanel(){
        JFreeChart chart =createChart(createDataset());
        CategoryPlot categoryplot =(CategoryPlot)chart.getCategoryPlot();
        BarRenderer renderer = new CustomRenderer(sortEntity.getIndex_i(), sortEntity.getIndex_j());
        //在柱子上显示相应信息 
        renderer.setBaseItemLabelsVisible(true);  
        CategoryTextAnnotation a = new CategoryTextAnnotation("_________________________________________________________", "", sortEntity.getPivot());   
        a.setCategoryAnchor(CategoryAnchor.START);   
        a.setFont(new Font("SansSerif", Font.PLAIN, 12)); 
        a.setTextAnchor(TextAnchor.BOTTOM_LEFT);   
        categoryplot.addAnnotation(a);  
        categoryplot.setRenderer(renderer);
        return new ChartPanel(chart); //将chart对象放入Panel面板中去,ChartPanel类已继承Jpanel
    }
}

这个使用的是JFreeChart 来进行构图的,具体的百度参考,需要的jar在文章的开头处

5.1自定义的BarRenderer

 

package com.edusys.utils;

import java.awt.Color;
import java.awt.Paint;

import org.jfree.chart.renderer.category.IntervalBarRenderer;

public class CustomRenderer extends IntervalBarRenderer  {
    private int index_i,index_j;
    private Paint[] colors;
    
    public CustomRenderer(int index_i,int index_j) {
        this.index_i=index_i;
        this.index_j=index_j;
        colors = new Paint[3];
        colors[0]=Color.RED;
        colors[1]=Color.RED;
        colors[2]=Color.GREEN;
    }
    
    public CustomRenderer() {
        super();
    }

    //对i,j赋予不同于其他柱子的颜色
    public Paint getItemPaint(int i, int j) {
        if(j==index_i){
            return colors[0];
        }else if(j==index_j){
            return colors[1];
        }else {
            return colors[2];
        }
    }
}

 

这里重写BarRenderer 类是为了对每次状态中的i,j进行特殊颜色处理,并规范JFreeChart 构图中的颜色

6.实现类

 

package com.edusys.ui;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


import com.edusys.utils.FileUtils;
import com.edusys.utils.HistogramUtils;
import com.edusys.utils.SortEntity;
import com.edusys.utils.SortUtils;
import com.edusys.utils.TimeUtils;


public class MainUI {
    
    private static int sort_type=0;
    private static int speed=1;
    private static int sleeptime=100;
    private static int count=0;
    private static boolean play_flag=false;
    private static boolean start_flag=false;
    private static List<SortEntity> sortList;
    
    public static void main(String[] args) {
        MainUI.animation();
    }
    /**
     * 算法动画演示
     */
    public static void animation(){
        final JFrame frame=new JFrame();
        
        frame.setSize(1000,620);
        frame.setVisible(true);
        frame.setResizable(false);
        frame.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width-1000)/2,
                (Toolkit.getDefaultToolkit().getScreenSize().height-620)/2);
        frame.setTitle("Algorithm Teaching System");
        frame.setLayout(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        sleeptime=100/speed;
        final SortUtils sortUtils=new SortUtils();
        if(sort_type==0){
            sortList=sortUtils.getQuickList();
        }else if(sort_type==1){
            sortList=sortUtils.getBubbleList();
        }else{
            sortList=sortUtils.getShellList();
        }
        int len=sortList.size();
        
        JPanel jPanel_sort=new JPanel();
        HistogramUtils histogramUtils=new HistogramUtils(sortList.get(count));
        jPanel_sort=histogramUtils.createPanel();
        frame.add(jPanel_sort);
        jPanel_sort.setBounds(0, 0, 450, 600);
        
        JLabel jLabel_title=new JLabel("Sort Algorithm");
        frame.add(jLabel_title);
        jLabel_title.setBounds(500, 20, 120, 30);
        JRadioButton jRadioButton_quick=new JRadioButton("Qucik Sort");
        frame.add(jRadioButton_quick);
        if(sort_type==0){
            jRadioButton_quick.setSelected(true);
        }
        jRadioButton_quick.setBounds(500, 50, 120, 30);
        jRadioButton_quick.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                sort_type=0;
                frame.dispose();
                MainUI.animation();
            }
        });
        JRadioButton jRadioButton_bubble=new JRadioButton("Bubble Sort");
        frame.add(jRadioButton_bubble);
        jRadioButton_bubble.setBounds(500, 80, 120, 30);
        if(sort_type==1){
            jRadioButton_bubble.setSelected(true);
        }
        jRadioButton_bubble.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                sort_type=1;
                frame.dispose();
                MainUI.animation();
            }
        });
        JRadioButton jRadioButton_shell=new JRadioButton("Shell Sort");
        frame.add(jRadioButton_shell);
        jRadioButton_shell.setBounds(500, 110, 120, 30);
        if(sort_type==2){
            jRadioButton_shell.setSelected(true);
        }
        jRadioButton_shell.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                sort_type=2;
                frame.dispose();
                MainUI.animation();
            }
        });
        ButtonGroup buttonGroup_sort=new ButtonGroup();
        buttonGroup_sort.add(jRadioButton_shell);
        buttonGroup_sort.add(jRadioButton_bubble);
        buttonGroup_sort.add(jRadioButton_quick);
        
        JLabel jLabel_speed=new JLabel("Speed");
        frame.add(jLabel_speed);
        jLabel_speed.setBounds(620, 160, 120, 30);
        
        JSlider jSlider_speed = new JSlider(1, 5, 1);
        frame.add(jSlider_speed);
        jSlider_speed.setBounds(500, 190, 300, 40);
        jSlider_speed.setMajorTickSpacing(1);
        jSlider_speed.setPaintTicks(true);
        jSlider_speed.setPaintLabels(true);
        jSlider_speed.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                speed=jSlider_speed.getValue();
                sleeptime=100/speed;
            }
        });
        
        JButton jButton_start=new JButton("Start");
        frame.add(jButton_start);
        jButton_start.setBounds(500, 320, 80, 30);
        jButton_start.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                start_flag=true;
                new Thread(){
                    @Override
                    public void run(){
                        while (count<len&&start_flag){
                            //休眠
                            try {
                                Thread.sleep(sleeptime);
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }

                            JPanel jPanel_sort=new JPanel();
                            HistogramUtils histogramUtils=new HistogramUtils(sortList.get(count));
                            jPanel_sort=histogramUtils.createPanel();
                            frame.add(jPanel_sort);
                            jPanel_sort.setBounds(0, 0, 450, 600);
                            count++;
                        }
                    }
                }.start();
                jButton_start.setEnabled(false);
            }
        });
        
        JButton jButton_restart=new JButton("Restart");
        frame.add(jButton_restart);
        jButton_restart.setBounds(600, 320, 80, 30);
        jButton_restart.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.dispose();
                MainUI.animation();
            }
        });
        
        JButton jButton_pause=new JButton("Pause");
        frame.add(jButton_pause);
        jButton_pause.setBounds(700, 320, 80, 30);
        jButton_pause.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                if(!play_flag){
                    start_flag=false;
                    jButton_pause.setText("Play");
                    play_flag=true;
                }else{
                    start_flag=true;
                    jButton_pause.setText("Pause");
                    play_flag=false;
                    new Thread(){
                        @Override
                        public void run(){
                            while (count<len&&start_flag){
                                //休眠
                                try {
                                    Thread.sleep(sleeptime);
                                } catch (InterruptedException e1) {
                                    e1.printStackTrace();
                                }

                                JPanel jPanel_sort=new JPanel();
                                HistogramUtils histogramUtils=new HistogramUtils(sortList.get(count));
                                jPanel_sort=histogramUtils.createPanel();
                                frame.add(jPanel_sort);
                                jPanel_sort.setBounds(0, 0, 450, 600);
                                count++;
                            }
                        }
                    }.start();
                }
            }
        });
        
        JButton jButton_forward=new JButton("Forward");
        frame.add(jButton_forward);
        jButton_forward.setBounds(800, 320, 80, 30);
        jButton_forward.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                if(count<len-1){
                    count++;
                    JPanel jPanel_sort=new JPanel();
                    HistogramUtils histogramUtils=new HistogramUtils(sortList.get(count));
                    jPanel_sort=histogramUtils.createPanel();
                    frame.add(jPanel_sort);
                    jPanel_sort.setBounds(0, 0, 450, 600);
                }
            }
        });
        
        JButton jButton_back=new JButton("Back");
        frame.add(jButton_back);
        jButton_back.setBounds(900, 320, 80, 30);
        jButton_back.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                if(count>0){
                    count--;
                    JPanel jPanel_sort=new JPanel();
                    HistogramUtils histogramUtils=new HistogramUtils(sortList.get(count));
                    jPanel_sort=histogramUtils.createPanel();
                    frame.add(jPanel_sort);
                    jPanel_sort.setBounds(0, 0, 450, 600);
                }
            }
        });
        
        JButton jButton_back2menu=new JButton("Back To Menu");
        frame.add(jButton_back2menu);
        jButton_back2menu.setBounds(700, 360, 120, 30);
        jButton_back2menu.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.dispose();
                MainUI.explanation();
            }
        });
        
        new Thread(){
            @Override
            public void run(){
                while (count<len&&start_flag){
                    //休眠
                    try {
                        Thread.sleep(sleeptime);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }

                    JPanel jPanel_sort=new JPanel();
                    HistogramUtils histogramUtils=new HistogramUtils(sortList.get(count));
                    jPanel_sort=histogramUtils.createPanel();
                    frame.add(jPanel_sort);
                    jPanel_sort.setBounds(0, 0, 450, 600);
                    count++;
                }
            }
        }.start();
    }
}

 

这里是实现类,线程上做的不是很好,因为对线程不是很了解,这里我也尝试过用while循环的,但是跳出去之后就不行了,重新打开另外的页面时,会卡死

因此这个线程虽然写的不是很好,但是刚刚能用

代码冗余,见谅!

 

效果图如下:

posted @ 2018-09-12 00:16  市井俗人  阅读(2550)  评论(7编辑  收藏  举报