Home > Back-end >  How to update Sorting Algorithm Visualization?
How to update Sorting Algorithm Visualization?

Time:07-05

I have been making a sorting algorithm visualizer in Java using Java Swing and AWT and coded insertion sort to see if it would be able to work. The algorithm works in the sense that when this program is run you can shuffle and sort the algorithm using insertion short but you don't actually see the algorithm in action. It just happens instantly and have been looking for ways to add some sort of delay but I can't find any sources to help me.

I set it up with 4 java classes, the main which just init's the window, the window class, array visualizer class, and the insertion sort class.

Window.java:

public class Window implements ActionListener  {
    
    //Window width
    protected static int WINDOW_WIDTH = 1980;
    //Window height
    protected static int WINDOW_HEIGHT = 1080;
    
    private int delay = 100;
    
    //This will draw all our rectangles 
    protected static ArrayVisualizer arrayVisualizer;
    
    //Make a new JFrame
    JFrame window = new JFrame();
    
    JButton shuffleBut = new JButton("Shuffle");
    
    JButton startSort = new JButton("Start Sorting");
    
    public Window() {
        initWindow();
    }
    
    private void addButtons() {
        
        //Shuffle Button
        shuffleBut.setBounds(100, 50, 100, 100);
        shuffleBut.setBackground(Color.white);
        shuffleBut.addActionListener(this);
        
        startSort.setBounds(500, 50, 100, 100);;
        startSort.setBackground(Color.white);
        startSort.addActionListener(taskPerformer);
        
        window.add(shuffleBut);
        window.add(startSort);
    }
    
    private void initWindow() {
        ImageIcon logo = new ImageIcon();
        
        window = new JFrame();
        window.setTitle("JAlgorithms");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        window.setLocationRelativeTo(null);
        window.setResizable(false);
        addButtons();
        
        arrayVisualizer = new ArrayVisualizer();
        window.add(arrayVisualizer);
        arrayVisualizer.repaint(); //Will call paint component method
        
        window.pack();
        window.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        if(e.getSource() == shuffleBut) {
            arrayVisualizer.shuffle(ArrayVisualizer.array);
            arrayVisualizer.repaint();
        }
    }
    ActionListener taskPerformer = new ActionListener() {
        public void actionPerformed(ActionEvent event) {
            if(event.getSource() == startSort) {
                arrayVisualizer.sort(ArrayVisualizer.array);
                arrayVisualizer.repaint();
            }   
        }
    };
    
}

ArrayVisualizer.java:

public class ArrayVisualizer extends JPanel {
    
    protected static int[] array;
    private final int REC_WIDTH = 1; //1980 rectangles
    private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
    
    public ArrayVisualizer() {
        array = new int[NUMBER_OF_RECS];
        generateRandom(array);
    }
    
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D graphics = (Graphics2D) g.create();
        graphics.setColor(Color.orange);
        for(int i = 0; i < NUMBER_OF_RECS; i  ) {
            
            int height = array[i] * 4; //Done for scaling
            int recX = i   (REC_WIDTH - 1) * i; //Read fillRect documentation
            int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
            
            graphics.fillRect(recX, recY, REC_WIDTH, height);
        }
    }
    
    
    //This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
    @Override
    public Dimension getPreferredSize() {   
        return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
    }
    
    //Creates a random unsorted array with numbers 1-200
    protected void generateRandom(int[] array) {
        Random number = new Random();
        for(int i = 0; i < NUMBER_OF_RECS; i  ) {
            array[i] = number.nextInt(200);
        }
    }
    
    protected void shuffle(int[] array) {
         generateRandom(array);
    }
    
    protected void sort(int[] array) {
         InsertionSort.insertionSort(array);
    }
}

InsertionSort.java:

public class InsertionSort {
    public static void insertionSort(int arr[])
    {
        int n = arr.length;
        
        
        for (int i = 1; i < n;   i) {

            int key = arr[i];
            int j = i - 1;
    
            /* Move elements of arr[0..i-1], that are
               greater than key, to one position ahead
               of their current position */
            while (j >= 0 && arr[j] > key) {
                arr[j   1] = arr[j];
                j = j - 1;
                
            }
            arr[j   1] = key;
            
        }
    }
}

UPDATE (Here is the modified code, I added selection sort as well and heavily modified the suggestion I checkmarked):

Main.java:

public class Main {

    public static void main(String[] args) {
        
        //Opens window
        Window window = new Window();
    }
}

Window.java:

import java.awt.Color;
import java.awt.Image;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.EventQueue;
import javax.swing.ImageIcon;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Window implements ActionListener  {
    
    //Window width
    protected static int WINDOW_WIDTH = 1440;
    //Window height
    protected static int WINDOW_HEIGHT = 1080;
        
    //This will draw all our rectangles 
    protected static ArrayVisualizer arrayVisualizer;
    
    //Make a new JFrame
    JFrame window = new JFrame();
    
    JButton shuffleBut = new JButton("Shuffle");
    
    JButton startSort = new JButton("Start Sorting");
    
    public Window() {
        initWindow();
    }
    
    private void addButtons() {
        
        //Shuffle Button
        shuffleBut.setBounds(100, 50, 100, 100);
        shuffleBut.setBackground(Color.white);
        shuffleBut.addActionListener(this);
        
        startSort.setBounds(500, 50, 100, 100);;
        startSort.setBackground(Color.white);
        
        window.add(shuffleBut);
        window.add(startSort);

    }
    
    private void initWindow() {
        ImageIcon logo = new ImageIcon();
        
        window = new JFrame();
        window.setTitle("JAlgorithms");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        window.setLocationRelativeTo(null);
        window.setResizable(false);
        addButtons();
        
        startSort.addActionListener(taskPerformer);

        arrayVisualizer = new ArrayVisualizer();
        window.add(arrayVisualizer);
        arrayVisualizer.repaint(); //Will call paint component method       
        
        window.pack();
        window.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        if(e.getSource() == shuffleBut) {
            arrayVisualizer.shuffle(ArrayVisualizer.array);
            arrayVisualizer.repaint();
        }
    }
    
    
    ActionListener taskPerformer = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent event) {
            if(event.getSource() == startSort) {
                if(!timer.isRunning()) { //If timer is not running
                    timer.setInitialDelay(0); //Set initial delay
                    timer.start();  //Start the timer
                }
            }   
        }
    };
    
    ActionListener sortWithDelay = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if(sorted(ArrayVisualizer.array)) { //If it is sorted
                timer.stop();   //Stop the timer
                return;
            } else {
                arrayVisualizer.sort(ArrayVisualizer.array); //If it is not sorted continue the sort
                arrayVisualizer.repaint();  //Called after each swap
            }
        }
    };
    
    private int delay = 10; //Milliseconds
    private Timer timer = new Timer(delay, sortWithDelay);
    
    private boolean sorted(int[] array) {
        for(int i = 0; i < array.length - 1; i  ) {
            if(array[i] > array[i 1]) {
                return false;
            }
        }
        return true;
    }
    
}

ArrayVisualizer.java:

import java.awt.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Array;

import javax.swing.*;
import java.util.*;

public class ArrayVisualizer extends JPanel {
    
    private static final long serialVersionUID = 1L;
    private InsertionSort insertionSort = new InsertionSort();
    private SelectionSort selectionSort = new SelectionSort();
    protected static int[] array;
    private final int REC_WIDTH = 1; //1980 rectangles
    private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
    private final int[] barColors;
    
    public ArrayVisualizer() {
        setBackground(Color.black);
        array = new int[NUMBER_OF_RECS];
        barColors = new int[NUMBER_OF_RECS];
        generateRandom(array);
    }
    
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D graphics = (Graphics2D) g.create();
        graphics.setColor(Color.white);
        for(int i = 0; i < NUMBER_OF_RECS; i  ) {
            
            int height = array[i] * 4; //Done for scaling
            int recX = i   (REC_WIDTH - 1) * i; //Read fillRect documentation
            int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
            
            
            graphics.fillRect(recX, recY, REC_WIDTH, height);
            
            
        }
    }
    
    
    //This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
    @Override
    public Dimension getPreferredSize() {   
        return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
    }
    
    //Creates a random unsorted array with numbers 1-200
    protected void generateRandom(int[] array) {
        Random number = new Random();
        for(int i = 0; i < NUMBER_OF_RECS; i  ) {
            array[i] = number.nextInt(200);
        }
    }
    
    protected void shuffle(int[] array) {
         generateRandom(array);
    }
    
    protected void sort(int[] array) {
        selectionSort.sortWithDelay(array);
    }
}

InsertionSort.java:

public class InsertionSort {
    
        private int i = 1;
        private int j = 0;

        public void sortWithDelay(int arr[])
        {
            int n = arr.length;
            
            if(i < n) {

                int key = arr[i];
                j = i - 1;
        
                /* Move elements of arr[0..i-1], that are
                   greater than key, to one position ahead
                   of their current position */
                while(j >= 0 && arr[j] > key) {
                    arr[j   1] = arr[j];
                    j = j - 1;
                }
                arr[j   1] = key;
                  i;
            }
        }
}

SelectionSort.java:

public class SelectionSort {

    private int i = 1;
    private int j = 0;
    
      public void sortWithDelay(int arr[])
        {
            int n = arr.length - 1;
      
            if(i < n) {
                
                int min_index = i;
                
                for(int j = i   1; j < n; j  ) {
                    if(arr[j] < arr[min_index]) {
                        min_index = j;
                    }
                }
                    int temp = arr[min_index];
                    arr[min_index] = arr[i];
                    arr[i] = temp;
                      i;
            }          
         }
      }

CodePudding user response:

Call an action with a swing timer every second that will return an intermediate array. Then paint this intermediate array. Repeat until the array is sorted.

To obtain an intermediate array, modify the InsertionSort from a static method to a class method that will store the variables i and j so that we can resume sorting when called again.

public class Window implements ActionListener  {
    
    //Window width
    protected static int WINDOW_WIDTH = 1980;
    //Window height
    protected static int WINDOW_HEIGHT = 1080;
    
    //This will draw all our rectangles 
    protected static ArrayVisualizer arrayVisualizer;
    
    //Make a new JFrame
    JFrame window = new JFrame();
    
    JButton shuffleBut = new JButton("Shuffle");
    
    JButton startSort = new JButton("Start Sorting");
    
    public Window() {
        initWindow();
    }
    
    private void addButtons() {
        
        //Shuffle Button
        shuffleBut.setBounds(100, 50, 100, 100);
        shuffleBut.setBackground(Color.white);
        shuffleBut.addActionListener(this);
        
        startSort.setBounds(500, 50, 100, 100);;
        startSort.setBackground(Color.white);
        startSort.addActionListener(taskPerformer);
        
        window.add(shuffleBut);
        window.add(startSort);
    }
    
    private void initWindow() {
        ImageIcon logo = new ImageIcon();
        
        window = new JFrame();
        window.setTitle("JAlgorithms");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        window.setLocationRelativeTo(null);
        window.setResizable(false);
        addButtons();
        
        arrayVisualizer = new ArrayVisualizer();
        window.add(arrayVisualizer);
        arrayVisualizer.repaint(); //Will call paint component method
        
        window.pack();
        window.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        if(e.getSource() == shuffleBut) {
            arrayVisualizer.shuffle(ArrayVisualizer.array);
            arrayVisualizer.repaint();
        }
    }

    private int delay = 1000; // delay is 1s
    private Timer timer = new Timer(delay, sortWithDelay);

    ActionListener taskPerformer = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent event) {
            if(event.getSource() == startSort) {
                // Start the timer that shows a swap every second
                if(!timer.isRunning()) {
                    timer.setInitialDelay(0);
                    timer.start();
                }
            }   
        }
    };

    ActionListener sortWithDelay = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent event) {
            if(isSorted(ArrayVisualizer.array)) {
                timer.stop();
                return;
            }
            arrayVisualizer.sort(ArrayVisualizer.array);
            arrayVisualizer.repaint();
        }
    };

    private boolean isSorted(int[] arr) {
        for (int i = 0; i < a.length - 1; i  ) {
            if (a[i] > a[i   1]) {
                return false;
            }
        }
        return true;
    }   
}
public class ArrayVisualizer extends JPanel {
    
    private InsertionSort insertionSort = new InsertionSort();
    protected static int[] array;
    private final int REC_WIDTH = 1; //1980 rectangles
    private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
    
    public ArrayVisualizer() {
        array = new int[NUMBER_OF_RECS];
        generateRandom(array);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D graphics = (Graphics2D) g.create();
        graphics.setColor(Color.orange);
        for(int i = 0; i < NUMBER_OF_RECS; i  ) {
            
            int height = array[i] * 4; //Done for scaling
            int recX = i   (REC_WIDTH - 1) * i; //Read fillRect documentation
            int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
            
            graphics.fillRect(recX, recY, REC_WIDTH, height);
        }
    }
        
    //This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
    @Override
    public Dimension getPreferredSize() {   
        return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
    }
    
    //Creates a random unsorted array with numbers 1-200
    protected void generateRandom(int[] array) {
        Random number = new Random();
        for(int i = 0; i < NUMBER_OF_RECS; i  ) {
            array[i] = number.nextInt(200);
        }
    }
    
    protected void shuffle(int[] array) {
         generateRandom(array);
    }
    
    protected void sort(int[] array) {
         insertionSort.sortWithDelay(array);
    }
}
public class InsertionSort {

    private int i = 1;
    private int j = 0;

    public void sortWithDelay(int arr[])
    {
        int n = arr.length;
        
        if(i < n) {

            int key = arr[i];
            j = i - 1;
    
            /* Move elements of arr[0..i-1], that are
               greater than key, to one position ahead
               of their current position */
            if(j >= 0 && arr[j] > key) {
                arr[j   1] = arr[j];
                j = j - 1;
                // return immediately after swap
                return;
            }
            arr[j   1] = key;
              i;
        }
    }
}
  • Related