7
\$\begingroup\$

Configs.java

package main;

/**
 * @author Daniel
 * 
 * A load of configs for the application.
 */

public class Configs {
    public static final String APPLICATION_NAME = "Sorting Algorithm Animation";

    public static final int APPLICATION_WIDTH = 1280;
    public static final int APPLICATION_HEIGHT = 720;

    public static final int DISPLAY_PANEL_WIDTH = Configs.APPLICATION_WIDTH * 4 / 5;
    public static final int DISPLAY_PANEL_HEIGHT = Configs.APPLICATION_HEIGHT;

    public static final int BUTTONS_PANEL_WIDTH = Configs.APPLICATION_WIDTH / 5;
    public static final int BUTTONS_PANEL_HEIGHT = Configs.APPLICATION_HEIGHT;

    public static final int INITIAL_LIST_STARTING_VALUE = 1024;

    public static final String[] ALL_SORTS_COMBO_BOX_VALUES = {"Bubble Sort", "Quick Sort", "Selection Sort", "Insertion Sort", "Merge Sort"};

    public static final int MAXIMUM_DELAY_VALUE = 10000;
    public static final int MINIMUM_DELAY_VALUE = 0;
    public static final int TICK_SPACING = 3333;



    public static final int INITIAL_DELAY_VALUE = MAXIMUM_DELAY_VALUE / 2;
}

SortingAlgorithmAnimationApp.java

package main;

import javax.swing.SwingUtilities;

import gui.AppGUI;

/**
 * @author Daniel
 * 
 * The driver class.
 */

public class SortingAlgorithmAnimationApp {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(AppGUI::new);
    }
}

AppGUI,java

package gui;

import java.awt.FlowLayout;

import javax.swing.JFrame;

import gui_components.GUIComponents;
import main.Configs;
import storage.NumbersList;

/**
 * @author Daniel
 * 
 * Puts the GUI  together.
 */

public class AppGUI {
    public AppGUI() {
        NumbersList.generateList(Configs.INITIAL_LIST_STARTING_VALUE);

        initGUI();
    }

    private void initGUI() {
        JFrame window = new JFrame();

        window.getContentPane().setLayout(new FlowLayout());

        window.getContentPane().add(GUIComponents.buttonsPanel);
        window.getContentPane().add(GUIComponents.displayPanel);

        window.setTitle(Configs.APPLICATION_NAME);
        window.setResizable(false);

        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.pack();

        window.setLocationRelativeTo(null);
        window.setVisible(true);

    }
}

GUIComponents.java

package gui_components;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;

import drawing.PaintSurface;
import main.Configs;
import sorting_algorithms.BubbleSort;
import sorting_algorithms.InsertionSort;
import sorting_algorithms.MergeSort;
import sorting_algorithms.QuickSort;
import sorting_algorithms.SelectionSort;
import sorting_algorithms.SortingAlgorithm;
import storage.NumbersList;

/**
 * @author Daniel
 * 
 * Creates and holds all the GUI components.
 */

public class GUIComponents {
    // don't let anyone instantiate this class.
    private GUIComponents() {}

    public static JPanel buttonsPanel, displayPanel;

    private static JButton newListButton;
    public static JSlider delaySlider;
    private static JButton randomizeListButton;
    private static JComboBox<String> allSortsComboBox;
    private static JButton doSortButton;

    private static SortingAlgorithm algorithm;

    static {
        initButtonsPanel();
        displayPanel = new PaintSurface();
    }

    private static void initButtonsPanel() {
        buttonsPanel = new JPanel();

        buttonsPanel.setPreferredSize(new Dimension(Configs.BUTTONS_PANEL_WIDTH, Configs.BUTTONS_PANEL_HEIGHT));
        buttonsPanel.setBackground(Color.LIGHT_GRAY);


        initNewListButton();
        initDelaySlider();
        initRandomizeListButton();
        initAllSortsComboBox();
        initDoSortButton();


        buttonsPanel.add(new JLabel("Sorting Delay (ms)"));
        buttonsPanel.add(delaySlider);

        buttonsPanel.add(newListButton);

        buttonsPanel.add(randomizeListButton);

        buttonsPanel.add(allSortsComboBox);
        buttonsPanel.add(doSortButton);
    }

    private static void initNewListButton() {
        newListButton = new JButton("New List");

        newListButton.addActionListener((ActionEvent event) -> {
            int amount = NumbersList.getList().length;

            try {
                String temp = JOptionPane.showInputDialog(null, "How many numbers?", "Enter Information", JOptionPane.INFORMATION_MESSAGE);
                if(temp != null && temp.length() > 0) {
                    amount = Integer.parseInt(temp);
                } else return;
            } catch(java.lang.NumberFormatException exception) {
                JOptionPane.showMessageDialog(null, "Something went wrong!", "Error", JOptionPane.ERROR_MESSAGE);
                return;
            }

            if(amount < 0 || amount > 1024) {
                JOptionPane.showMessageDialog(null, "Invalid Amount! 0 - 1024 only.", "Error", JOptionPane.ERROR_MESSAGE);
                return;
            }

            NumbersList.generateList(amount);
            GUIComponents.displayPanel.repaint();
        });
    }

    private static void initDelaySlider() {
        delaySlider = new JSlider(JSlider.HORIZONTAL, Configs.MINIMUM_DELAY_VALUE, Configs.MAXIMUM_DELAY_VALUE, Configs.INITIAL_DELAY_VALUE);
        delaySlider.setMajorTickSpacing(Configs.TICK_SPACING);
        delaySlider.setMinorTickSpacing(10);
        delaySlider.setPaintLabels(true);
        delaySlider.setSnapToTicks(true);
        delaySlider.setBackground(Color.LIGHT_GRAY);

        delaySlider.addChangeListener((ChangeEvent event) -> {
            if(algorithm != null)
                algorithm.changeDelay(delaySlider.getValue() * 1000);
        });
    }

    private static void initRandomizeListButton() {
        randomizeListButton = new JButton("Randomize List");
        randomizeListButton.addActionListener((ActionEvent event) -> {
            NumbersList.randomizeList();
            GUIComponents.displayPanel.repaint();
        });
    }

    private static void initAllSortsComboBox() {
        allSortsComboBox = new JComboBox<String>(Configs.ALL_SORTS_COMBO_BOX_VALUES);
    }

    private static void initDoSortButton() {
        doSortButton = new JButton("Do Sort");

        doSortButton.addActionListener((ActionEvent event) -> {
            randomizeListButton.setEnabled(false);
            newListButton.setEnabled(false);
            doSortButton.setEnabled(false);
            allSortsComboBox.setEnabled(false);

            switch((String) allSortsComboBox.getSelectedItem()) {

            case "Bubble Sort":
                algorithm = new BubbleSort();
                break;

            case "Quick Sort":
                algorithm = new QuickSort();
                break;

            case "Selection Sort":
                algorithm = new SelectionSort();
                break;

            case "Insertion Sort":
                algorithm = new InsertionSort();
                break;

            case "Merge Sort":
                algorithm = new MergeSort();
                break;
            }

            new Thread(new Runnable() {
                @Override
                public void run() {
                    algorithm.doSort(NumbersList.getList());

                    randomizeListButton.setEnabled(true);
                    newListButton.setEnabled(true);
                    doSortButton.setEnabled(true);
                    allSortsComboBox.setEnabled(true);
                }}).start();



            displayPanel.repaint();
        });
    }
}

NumbersList.java

package storage;

import main.Configs;

/**
 * @author Daniel
 * 
 * Holds the list and methods concerning the list.
 */

public class NumbersList {
    private static int[] numbers;

    public static void generateList(int amount) {
        numbers = new int[amount];

        double spacing = (double) Configs.APPLICATION_HEIGHT / amount, height = spacing;
        for(int i = 0; i < amount; i++) {
            numbers[i] = (int) (height);

            height += spacing;
        }
    }

    public static void randomizeList() {
        for(int i = 0; i < NumbersList.numbers.length; i++) {
            int temp = NumbersList.numbers[i];
            int randomPlace = (int) (Math.random() * NumbersList.numbers.length);

            NumbersList.numbers[i] = NumbersList.numbers[randomPlace];
            NumbersList.numbers[randomPlace] = temp;
        }
    }

    public static int[] getList() {
        return NumbersList.numbers;
    }
}

PaintSurface.java

package drawing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JPanel;

import main.Configs;
import storage.NumbersList;

/**
 * @author Daniel
 * 
 * The display panel for the animation.
 */

public class PaintSurface extends JPanel {
    private static final long serialVersionUID = 1L;

    public static int currentBarIndex = 0;

    public PaintSurface() {
        this.setPreferredSize(new Dimension(Configs.DISPLAY_PANEL_WIDTH, Configs.DISPLAY_PANEL_HEIGHT));

        this.setBackground(Color.PINK);
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D graphics = (Graphics2D) g;
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        super.paintComponent(graphics);

        int[] listNumbers = NumbersList.getList();

        double x = 0, width = (double) Configs.DISPLAY_PANEL_WIDTH / listNumbers.length;
        for(int i = 0; i < listNumbers.length; i++) {
            if(currentBarIndex == i)
                graphics.setPaint(Color.RED);
            else
                graphics.setPaint(Color.BLACK);

            graphics.fillRect((int) x, Configs.APPLICATION_HEIGHT - listNumbers[i], (int) width + 1, listNumbers[i]);

            x += width;
        }

        graphics.dispose();
        g.dispose();
    }
}

BubbleSort.java

package sorting_algorithms;

import gui_components.GUIComponents;

/**
 * @author Daniel
 * 
 * Implementation of the bubble sort.
 */

public class BubbleSort implements SortingAlgorithm {
    private int delay = GUIComponents.delaySlider.getValue() * 1000;

    @Override
    public String getName() {
        return "Bubble Sort";
    }

    @Override
    public void doSort(int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n - 1; i++)
            for (int j = 0; j < n - i - 1; j++)
                if (nums[j] > nums[j + 1]) {
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;

                    SortingAlgorithm.setCurrentBar(j+1);
                    SortingAlgorithm.sleepFor(delay);
                }

        SortingAlgorithm.setCurrentBar(0);
    }

    @Override
    public void changeDelay(int delay) {
        this.delay = delay;
    }
}

QuickSort.java

package sorting_algorithms;

import gui_components.GUIComponents;

public class QuickSort implements SortingAlgorithm {
    private int delay = GUIComponents.delaySlider.getValue() * 1000;

    @Override
    public String getName() {
        return "Quick Sort";
    }

    @Override
    public void doSort(int[] nums) {
        sort(nums, 0, nums.length - 1);
    }

    private int partition(int nums[], int low, int high) {
        int pivot = nums[high];
        int i = (low - 1);
        for (int j = low; j < high; j++) {
            if (nums[j] < pivot) {
                i++;

                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;

                SortingAlgorithm.setCurrentBar(j);
                SortingAlgorithm.sleepFor(delay);
            }
        }

        int temp = nums[i + 1];
        nums[i + 1] = nums[high];
        nums[high] = temp;

        return i + 1;
    }

    private void sort(int nums[], int low, int high) {
        if (low < high) {
            int pi = partition(nums, low, high);

            sort(nums, low, pi - 1);
            sort(nums, pi + 1, high);
        }
    }

    @Override
    public void changeDelay(int delay) {
        this.delay = delay;
    }
}

SelectionSort.java

package sorting_algorithms;

import gui_components.GUIComponents;

/**
 * @author Daniel
 * 
 * Implementation of the selection sort.
 */

public class SelectionSort implements SortingAlgorithm {
    private int delay = GUIComponents.delaySlider.getValue() * 1000;

    @Override
    public String getName() {
        return "Selection Sort";
    }

    @Override
    public void doSort(int[] nums) {
        int n = nums.length;

        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < n; j++)
                if (nums[j] < nums[minIndex]) {
                    minIndex = j;

                    SortingAlgorithm.setCurrentBar(i);
                    SortingAlgorithm.setCurrentBar(j);
                    SortingAlgorithm.sleepFor(delay);
                }

            int temp = nums[minIndex];
            nums[minIndex] = nums[i];
            nums[i] = temp;
        }
    }

    @Override
    public void changeDelay(int delay) {
        this.delay = delay;
    }
}

InsertionSort.java

package sorting_algorithms;

import gui_components.GUIComponents;

/**
 * @author Daniel
 * 
 * Implementation of the insertion sort.
 */

public class InsertionSort implements SortingAlgorithm {
    private int delay = GUIComponents.delaySlider.getValue() * 1000;

    @Override
    public String getName() {
        return "Insertion Sort";
    }

    @Override
    public void doSort(int[] nums) {
        int n = nums.length;

        for (int i = 1; i < n; ++i) {
            int key = nums[i];
            int j = i - 1;

            while (j >= 0 && nums[j] > key) {
                nums[j + 1] = nums[j];
                j--;
            }
            nums[j + 1] = key;

            SortingAlgorithm.setCurrentBar(j);
            SortingAlgorithm.sleepFor(delay);
        }
    }

    @Override
    public void changeDelay(int delay) {
        this.delay = delay;
    }
}

MergeSort.java

package sorting_algorithms;

import gui_components.GUIComponents;

public class MergeSort implements SortingAlgorithm {
    private int delay = GUIComponents.delaySlider.getValue() * 1000;

    @Override
    public String getName() {
        return "Merge Sort";
    }

    @Override
    public void doSort(int[] nums) {
        sort(nums, 0, nums.length - 1);
    }

    private void merge(int nums[], int l, int m, int r) {
        int n1 = m - l + 1;
        int n2 = r - m;

        int L[] = new int[n1];
        int R[] = new int[n2];

        for(int i = 0; i < n1; ++i)
            L[i] = nums[l + i];

        for(int j = 0; j < n2; ++j)
            R[j] = nums[m + 1 + j];

        int i = 0, j = 0;

        int k = l;
        while (i < n1 && j < n2) {
            if (L[i] <= R[j]) {
                nums[k] = L[i];
                i++;

                SortingAlgorithm.setCurrentBar(j);
                SortingAlgorithm.sleepFor(delay);

            } else {
                nums[k] = R[j];
                j++;

                SortingAlgorithm.setCurrentBar(j);
                SortingAlgorithm.sleepFor(delay);
            }
            k++;
        }

        while (i < n1) {
            nums[k] = L[i];
            i++;
            k++;

            SortingAlgorithm.setCurrentBar(j);
            SortingAlgorithm.sleepFor(delay);
        }

        while (j < n2) {
            nums[k] = R[j];
            j++;
            k++;

            SortingAlgorithm.setCurrentBar(j);
            SortingAlgorithm.sleepFor(delay);
        }
    }

    private void sort(int nums[], int l, int r) {
        if (l < r) {
            int m = (l + r) / 2;

            sort(nums, l, m);
            sort(nums, m + 1, r);

            merge(nums, l, m, r);
        }
    }

    @Override
    public void changeDelay(int delay) {
        this.delay = delay;
    }
}

SortingAlgorithm.java

package sorting_algorithms;

import drawing.PaintSurface;
import gui_components.GUIComponents;

/**
 * @author Daniel
 * 
 * Template for the sorting algorithms.
 */

public abstract interface SortingAlgorithm {
    public abstract String getName();

    public abstract void doSort(int[] nums);

    public abstract void changeDelay(int delay);

    public static void setCurrentBar(int currentBarIndex) {
        PaintSurface.currentBarIndex = currentBarIndex;
    }

    public static void sleepFor(int delay) {
        long timeElapsed;
        final long startTime = System.nanoTime();

        do {
            timeElapsed = System.nanoTime() - startTime;
        } while(timeElapsed < delay);

        GUIComponents.displayPanel.repaint();
    }
}

Any helpful recommendations, comments, or suggestions are great. I'm only in high school, so any constructive criticism is nice! Thanks!

\$\endgroup\$
1
  • \$\begingroup\$ Welcome to CodeReview@SE! Have a (another) look at How do I ask a Good Question? and try and find a better title - I think simulation slightly off, as the sorting is as real as it comes, with visualisation welded in. It may prove useful to present more context: what details of interface SortingAlgorithm are your own design, what was specified beforehand? \$\endgroup\$ – greybeard Mar 3 '20 at 6:44
4
\$\begingroup\$

Welcome to CodeReview, your program is advanced for high school. I have some suggestions for you:

private int delay = GUIComponents.delaySlider.getValue() * 1000;

You repetead this line all the classes implementing one different sorting method, you could use a constructor and pass this as a value like the class below:

public class BubbleSort implements SortingAlgorithm {

    private int delay;

    public BubbleSort(int delay) {
        this.delay = delay;
    }

    //other methods
}

//after in your code
int delay = GUIComponents.delaySlider.getValue() * 1000;
SortingAlgorithm bubble = new BubbleSort(delay);

I don't know if you are aware about the Map class, that maps keys to value, you could use in the following way:

int delay = GUIComponents.delaySlider.getValue() * 1000;
Map<String, SortingAlgorithm> map = new TreeMap<String, SortingAlgorithm>();
map.put("Bubble sort", new BubbleSort(delay));
map.put("Quick sort", new QuickSort(delay));
Set<String> set = map.keySet(); //[Bubble sort, Quick sort]
SortingAlgorithm bubble = map.get("Bubble sort");
SortingAlgorithm quick = map.get("Quick sort");

In this example I created one BubbleSort object and one QuickSort object mapping them with their labels by put method and you can access them using the get method.

One thing you could change is the name of the class NumbersList : List is about a structure that can be modified while your class is an array, perhaps you could rename it as NumbersArray. Below my implementation for your class:

public class NumbersArray {
    private static int[] numbers;

    public static void generateArray(int amount) {
        numbers = new int[amount];

        double spacing = (double) Configs.APPLICATION_HEIGHT / amount;
        for(int i = 0; i < amount; i++) {
            numbers[i] = (int) ((i + 1) * spacing);
        }
    }

    public static void randomizeArray() {
        Collections.shuffle(Arrays.asList(numbers));
    }

    public static int[] getArray() {
        return numbers;
    }
}

I used Collections.shuffle method to randomize the elements of your array. Anyway again you made a great job.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.