【算法筆記】Java Swing實現選擇排序算法可視化

前言

最近看劉老師視頻重新學習算法,記錄下學習過程。

選擇排序算法

選擇排序算法是交換算法的一種。
每一次都從待排序的數據組合裏找到最小(或最大)的一個元素放到已排好序的序列中。
選擇排序算法核心代碼:

    public void selectSort(int [] arr){
        for (int i = 0; i < arr.length; i++) {
            int minIndex = i;
            int j;
            // 找出最小值的元素下標
            for (j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex]) {
                   // 保存當前找到的最小值的元素下標
                    minIndex = j;
                }
            }
            // 將目前找到的最小值放到有序隊列中
            int tmp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = tmp;
        }
    }

可視化

用四種顏色動態展示排序過程。(在此展示的是由小到大的排序)
灰色:待排序元素
紅色:已有序元素
藍色:正在遍歷的元素
紫色:目前選出的最小元素

數據層:SelectionSortData.java

package Demo;

public class SelectionSortData {

    private int[] number;

    public int orderedIndex = -1;   // 在[0,orderedIndex]內是有序的
    public int currentCompareIndex = -1;  // 當前正在比較的元素下標
    public int currentMinIndex = -1;  // 當前找到的最小值的元素下標

    public SelectionSortData(int randomBound,int N){
        if(randomBound <=0 || N<=0)
            throw new IllegalArgumentException("SceneHeight or N must larger than 0 ");
        number = new int[N];
        // 生成隨機數組
        for(int i=0;i<N;i++){
            number[i] = (int)(Math.random()*randomBound) + 1;
        }
    }

   // 獲得數組指定下標的元素
    public int getNumber(int i){
        if ( i < 0 || i >= number.length )
            throw new IllegalArgumentException("out of index ");
        return number[i];
    }

   // 獲得數組長度
    public int getN() {
        return number.length;
    }

    // 元素交換
    public void swap(int i,int j){
        int temp = number[i];
        number[i] = number[j];
        number[j] = temp;
    }

}

視圖層:SortFrame.java

package Demo;

import javax.swing.*;
import java.awt.*;

public class SortFrame extends JFrame {

    private int canvasWidth;
    private int canvasHeight;

    public SortFrame(String title,int canvasWidth,int canvasHeight){
        super(title);
        // 畫布
        SortCanvas sortCanvas = new SortCanvas();
        setContentPane(sortCanvas);
        this.canvasWidth = canvasWidth;
        this.canvasHeight = canvasHeight;
        setSize(canvasWidth,canvasHeight);  // 設置窗口大小
        setResizable(true);  // 窗口可進行縮放
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();  // 窗口大小自適應
        setVisible(true);  // 窗口可見
    }

    // 數據內容渲染
    private SelectionSortData data;
    public void render(SelectionSortData data){
        this.data = data;
        repaint();
    }

    private class SortCanvas extends JPanel{
        public SortCanvas(){
            super(true);   // 允許雙緩存
        }

        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g);

            Graphics2D graphics2D = (Graphics2D)g;
            // 抗鋸齒
            RenderingHints renderingHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            graphics2D.addRenderingHints(renderingHints);

            // 具體繪製
            int w = canvasWidth / data.getN();  // 矩形寬度
            for(int i=0;i<data.getN();i++){
                if(i < data.orderedIndex)   // 已有序的數組元素
                    SortVisHelper.setColor(graphics2D,Color.RED); 
                else   // 無序的數組元素
                    SortVisHelper.setColor(graphics2D,Color.GRAY);

                if(i == data.currentCompareIndex)  // 正在進行比較的元素 
                    SortVisHelper.setColor(graphics2D,Color.BLUE);
                if(i == data.currentMinIndex)  // 當前找到的最小值的元素
                    SortVisHelper.setColor(graphics2D,Color.MAGENTA);
				// 畫矩形
                SortVisHelper.filledRectangle(graphics2D,i*w,canvasHeight-data.getNumber(i),w-1,data.getNumber(i));
            }

        }

        @Override
        public Dimension getPreferredSize(){
            return  new Dimension(canvasWidth,canvasHeight);
        }

    }
}

控制層:SortVisualizer.java

package Demo;

import java.awt.*;

public class SortVisualizer {

    private SelectionSortData data; // 數據
    private SortFrame sortFrame; // 視圖

    publicSortVisualizer(int sceneWidth,int sceneHeight,int N){
        // 初始化數據
        data = new SelectionSortData(sceneHeight,N);

        // 初始化視圖
        sortFrame = new SortFrame("選擇排序",sceneWidth,sceneHeight);
        EventQueue.invokeLater(()->{
            new Thread(()->{
                run();
            }).start();
        });
    }

    // 動畫邏輯
    private void run(){
       // 更新繪製
        setData(0,-1,-1);
        // 選擇排序算法
        for(int i = 0;i < data.getN();i++){
              int minIndex = i;
              setData(i,-1,minIndex);
              for(int j = i+1;j < data.getN();j++){
                  setData(i,j,minIndex);
                  if(data.getNumber(j) < data.getNumber(minIndex))
                      minIndex = j;
                      setData(i,j,minIndex);
              }
              data.swap(i,minIndex);
              setData(i+1,-1,-1);
          }
          setData(data.getN(),-1,-1);
    }

  // 實時更新元素狀態
    public void setData(int orderedIndex,int currentCompareIndex,int currentMinIndex){
        data.orderedIndex = orderedIndex;
        data.currentCompareIndex = currentCompareIndex;
        data.currentMinIndex = currentMinIndex;

        sortFrame.render(data);
        SortVisHelper.pause(50);
    }
}

畫圖輔助類:SortVisHelper.java

package Demo;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;

public class SortVisHelper {
   // 不允許外部類實例化
    private SortVisHelper(){}

    // 設置顏色
    public static void setColor(Graphics2D g,Color color){
        g.setColor(color);
    }

    // 空心矩形
    public static void storkeRectangle(Graphics2D g,int x,int y,int w,int h){
        Rectangle2D rectangle = new Rectangle2D.Double(x,y,w,h);
        g.draw(rectangle);
    }

    // 實心矩形
    public static void filledRectangle(Graphics2D g,int x,int y,int w,int h){
        Rectangle2D rectangle = new Rectangle2D.Double(x,y,w,h);
        g.fill(rectangle);
    }


    // 暫停
    public static void pause(int time){
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章