1

My program visually demonstrates a sequential version of the well known QuickSort algorithm, with two new visual demonstrations: (I) a parallel version of QuickSort, implemented using low level Thread API and SwingUtilities, and (II) a parallel version of QuickSort, implemented using SwingWorker API.

I am trying to have a facility to restart the program after a successful run. Currently, the buttons are disabled when the sorting operation starts, which is correct, but they never re-enable and so I was wondering if there is a way to enable all the buttons after the successful run? Some of the code is as follows:

// http://www.java2s.com/Code/Java/Collections-Data-Structure/Animationforquicksort.htm
// http://www.sorting-algorithms.com/quick-sort

import java.lang.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.util.*;
import javax.swing.*;
import java.util.concurrent.atomic.*;

public class QuickSortVisualizer implements Runnable {
    static int LENGTH = 32;
    static int LEFT = 500;
    static int RIGHT = 500;
    static int SWAP = 1000;

    int[] Values;
    AtomicInteger WorkerThreads = new AtomicInteger();

    public static void main(String[] args) {
        try {
            if (args.length == 0) {             
                LENGTH = 32;
                LEFT = 500;
                RIGHT = 500;
                SWAP = 1000;

            } else if (args.length == 4) { 
                //dw about this



            } else {
                throw new Exception("incorrect command-line argument count"); 
            }

            System.err.format("... LENGTH=%d LEFT=%d RIGHT=%d SWAP=%d%n", LENGTH, LEFT, RIGHT, SWAP);
            SwingUtilities.invokeAndWait(new QuickSortVisualizer());
            System.err.format("... GUI started%n");

        } catch (Exception ex) {
            System.err.format("*** %s%n", ex.getMessage());
        }
    }

    JButton BoredButton;
    JButton WorkerButtonSequential;
    JButton WorkerButtonThreads;
    JButton WorkerButtonSwingWorkers;
    SorterPanel MySortPanel;
    JLabel StatusBar;

    public void run() {
        JFrame frame = new JFrame();
        frame.setTitle("My Quick Sort Visualizer");
        Font font = new Font("Monospaced", Font.BOLD, 18);

        BoredButton = new JButton("I am bored");
        BoredButton.setFont(font);
        BoredButton.setPreferredSize(new Dimension(180, 30));
        BoredButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                BoredButton_Click();
            }
        });

        WorkerButtonSequential = new JButton("QS Sequential");
        WorkerButtonSequential.setFont(font);
        WorkerButtonSequential.setPreferredSize(new Dimension(185, 30));
        WorkerButtonSequential.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                WorkerButtonSequential_Click();
            }
        });

        WorkerButtonThreads = new JButton("QS Threads");
        WorkerButtonThreads.setFont(font);
        WorkerButtonThreads.setPreferredSize(new Dimension(185, 30));
        WorkerButtonThreads.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                WorkerButtonThreads_Click();
            }
        });

        WorkerButtonSwingWorkers = new JButton("QS SwingWorkers");
        WorkerButtonSwingWorkers.setFont(font);
        WorkerButtonSwingWorkers.setPreferredSize(new Dimension(200, 30));
        WorkerButtonSwingWorkers.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                WorkerButtonSwingWorkers_Click();
            }
        });

        JPanel strip = new JPanel(new FlowLayout(FlowLayout.CENTER));
        strip.add(BoredButton);
        strip.add(WorkerButtonSequential);
        strip.add(WorkerButtonThreads);
        strip.add(WorkerButtonSwingWorkers);
        frame.getContentPane().add(strip, BorderLayout.NORTH);

        StatusBar = new JLabel();
        StatusBar.setFont(font);
        StatusBar.setPreferredSize(new Dimension(800, 20));
        frame.getContentPane().add(StatusBar, BorderLayout.SOUTH);

        MySortPanel = new SorterPanel();
        frame.getContentPane().add(MySortPanel, BorderLayout.CENTER);

        frame.getRootPane().setDefaultButton(BoredButton);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 400);
        frame.setResizable(true);
        frame.setVisible(true);
    }

    public void BoredButton_Click() {
        String text = Calendar.getInstance().getTime().toString();
        StatusBar.setText(text);
        System.err.format("... now %s%n", text);
    }

    public void WorkerButtonSequential_Click() {
        WorkerButtonSequential.setEnabled(false);
        WorkerButtonThreads.setEnabled(false);
        WorkerButtonSwingWorkers.setEnabled(false);
        System.err.format("... sequential%n");

        QSSequential();
    }

    public void WorkerButtonThreads_Click() {
        WorkerButtonSequential.setEnabled(false);
        WorkerButtonThreads.setEnabled(false);
        WorkerButtonSwingWorkers.setEnabled(false);
        int processors = Runtime.getRuntime().availableProcessors();
        int threshold = processors * 2;
        System.err.format("... parallel threads: processors=%d threshold=%d%n", processors, threshold);
        QSThreads(threshold);
    }

    public void WorkerButtonSwingWorkers_Click() {
        WorkerButtonSequential.setEnabled(false);
        WorkerButtonThreads.setEnabled(false);
        WorkerButtonSwingWorkers.setEnabled(false);
        int processors = Runtime.getRuntime().availableProcessors();
        int threshold = processors * 2;
        System.err.format("... parallel swingworkers: processors=%d threshold=%d%n", processors, threshold);
        QSSwingWorkers(threshold);
    }

    void QSInit() {
        Values = new int[LENGTH];
        for (int i = 0; i < Values.length; i++) {
            Values[i] = (int)Math.round(Math.random() * (MySortPanel.getHeight()-10));
        }
        print("... initial values");                

        MySortPanel.setValues(Values);      
    }

    void QSSequential() {
        QSInit();

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                QuickSortSequential qss = new QuickSortSequential(Values, 0, Values.length - 1, MySortPanel);
                System.err.format("... started%n");
                qss.run();

                DoneAll();
            }
        });
    }

    void QSThreads(int threshold) {
        QSInit();

        QuickSortThread qst = new QuickSortThread(Values, 0, Values.length - 1, threshold, MySortPanel);
        WorkerThreads.set(0);
        incWorkerThreads();
        System.err.format("... started%n");
        qst.start();
    }

    void QSSwingWorkers(int threshold) {
        QSInit();

        QuickSortWorker qsw = new QuickSortWorker(Values, 0, Values.length - 1, threshold, MySortPanel);
        WorkerThreads.set(0);
        incWorkerThreads();
        System.err.format("... started%n");
        qsw.execute();      
    }

    void print(String caption) {
        System.err.format("%s%n", caption);
        for (int i=0; i<Values.length; i++) {
            System.err.format(" %d:%d", i, Values[i]);
        }
        System.err.format("%n");
    }

    void incWorkerThreads() {
        int w = WorkerThreads.incrementAndGet();
        System.err.format("... workers=%d%n", w);
    }

    void decWorkerThreads() {
        int w = WorkerThreads.decrementAndGet();
        System.err.format("... workers=%d%n", w);
        if (w <= 0) DoneAll();
    }

    void DoneAll() {
        print("... sorted values");                 
        WorkerButtonSequential.setEnabled(true);    
        WorkerButtonThreads.setEnabled(true);       
        WorkerButtonSwingWorkers.setEnabled(true);      
        System.err.format("%n");
    }

    // === SorterPanel

    /* colour codes
    pivot : YELLOW
    left item : GREEN
    right item : BLUE
    left item just before swap : PINK
    right item just before swap : PINK
    left item just after swap : RED
    right item just after swap : RED
    */

    class SorterPanel extends JComponent {
        int[] Values;       
        int width;
        Graphics2D g2;
        Color pen;
        Color back;

        public void setValues(int[] Values) {
            this.Values = Values;
            width = super.getWidth() / Values.length;
            repaint();
        }

        @Override 
        public void paintComponent(Graphics g) {
            if (Values == null) return;

            g2 = (Graphics2D) g;
            pen = Color.BLACK; // g2.getColor();
            back = g2.getBackground();

            for (int i = 0; i < Values.length; i++) {
                g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, Values[i]));
            }
        }

        public void mark(int i, int value, Color m) {
            g2 = (Graphics2D) super.getGraphics();
            pen = g2.getColor();
            g2.setColor(m);
            //g2.fill(new Rectangle2D.Double(width*i+2, 1, width-4, Values[i]-2));
            g2.fill(new Rectangle2D.Double(width*i+2, 1, width-4, value-2));
            g2.setColor(pen);
        }

        public void unmark(final int i, final int value) {
            mark(i, value, back);
        }

        public void erase(int i, int value) {
            g2 = (Graphics2D) super.getGraphics();
            //g2.clearRect(width*i+1, 0, width-1, Values[i]+1);
            g2.clearRect(width*i+1, 0, width-1, value+1);
        }

        public void redraw(int i, int value) {
            g2 = (Graphics2D) super.getGraphics();
            //g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, Values[i]));
            g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, value));
            mark(i, value, back);
        }
    }

    // === QuickSort Sequential

    class QuickSortSequential implements Runnable { 
        int[] array;
        int left;
        int right;

        // === GUI stuff

        SorterPanel sortpan;

        void publish(Runnable gui_update) {
            gui_update.run();
        }

        void mark(final int idx, final Color color) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.mark(idx, value, color); 
                }
            });
        }

        void unmark(final int idx) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.unmark(idx, value); 
                }
            });
        }

        void erase(final int idx) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.erase(idx, value); 
                }
            });
        }

        void redraw(final int idx) {
            final int value = array[idx];
            publish(new Runnable() { 
                public void run() { 
                    sortpan.redraw(idx, value); 
                }
            });
        }

        void sleep(int period) {
            try { 
                Thread.sleep(period); 
            } catch (Exception ex) { 
                System.err.format("%s%n", ex.getMessage()); 
            }                   
        }

        // === stuff

        public QuickSortSequential(final int array[], final int left, final int right, final SorterPanel sortpan) {
            this.array = array;
            this.left = left;
            this.right = right;
            this.sortpan = sortpan;
        }

        public void run() {
            QuickSort();
        }

        // === QuickSort stuff

        void QuickSort() {
            if (left >= right) return;
            final int pivot = Partition();
            if (pivot < 0) return;

            QuickSortSequential lquick = new QuickSortSequential(array, left, pivot-1, sortpan);
            QuickSortSequential rquick = new QuickSortSequential(array, pivot, right, sortpan);

            lquick.run();
            rquick.run();
        }

        int Partition() {
            int leftIdx = left;
            int rightIdx = right;
            int pivotIdx = (left + right) / 2;
            final int pivot = array[pivotIdx]; 

            while (true) {
                if (leftIdx > rightIdx) break;

                mark(pivotIdx, Color.YELLOW);
                mark(leftIdx, Color.GREEN);
                mark(rightIdx, Color.BLUE);
                sleep(LEFT);

                while (true) {
                    if (array[leftIdx] >= pivot) break;
                    else {
                        unmark(leftIdx);
                        leftIdx += 1;
                        mark(pivotIdx, Color.YELLOW);
                        mark(leftIdx, Color.GREEN);
                        sleep(LEFT);
                    }
                }

                while (true) {
                    if (pivot >= array[rightIdx]) break;
                    else {
                        unmark(rightIdx);
                        rightIdx -= 1;
                        mark(pivotIdx, Color.YELLOW);
                        mark(rightIdx, Color.BLUE);
                        sleep(RIGHT);
                    }
                }

                unmark(pivotIdx);
                unmark(leftIdx);
                unmark(rightIdx);

                if (leftIdx <= rightIdx) {                  
                    if (leftIdx < rightIdx) {
                        mark(pivotIdx, Color.YELLOW);
                        mark(leftIdx, Color.PINK);
                        mark(rightIdx, Color.PINK);
                        sleep(SWAP);

                        erase(leftIdx);
                        erase(rightIdx);

                        int temp = array[rightIdx];
                        array[rightIdx] = array[leftIdx];
                        array[leftIdx] = temp;

                        if (pivotIdx == leftIdx) pivotIdx = rightIdx;
                        else if (pivotIdx == rightIdx) pivotIdx = leftIdx;

                        redraw(leftIdx);
                        redraw(rightIdx);

                        mark(pivotIdx, Color.YELLOW);
                        mark(leftIdx, Color.RED);
                        mark(rightIdx, Color.RED);
                        sleep(SWAP);

                    }

                    unmark(pivotIdx);
                    unmark(leftIdx);
                    unmark(rightIdx);

                    leftIdx += 1;
                    rightIdx -= 1;
                }
            }

            return leftIdx;
        }
    }

    // === QuickSort with Threads

    class QuickSortThread extends Thread { 
        int[] array;
        int left;
        int right;
        int threshold;

        // === GUI stuff

        SorterPanel sortpan;



        // === Thread etc stuff

        public QuickSortThread(final int array[], final int left, final int right, final int threshold, final SorterPanel sortpan) {
            this.array = array;
            this.left = left;
            this.right = right;
            this.sortpan = sortpan;
            this.threshold = threshold;
        }

        @Override
        public void run() {

            decWorkerThreads();
        }


    }

    // === QuickSort with SwingWorkers

    class QuickSortWorker extends SwingWorker<Boolean, Runnable> {  
        int[] array;
        int left;
        int right;
        int threshold;

        // === GUI stuff 

        SorterPanel sortpan;



        // === SwingWorker stuff

        public QuickSortWorker(final int array[], final int left, final int right, final int threshold, final SorterPanel sortpan) {
            this.array = array;
            this.left = left;
            this.right = right;
            this.threshold = threshold;
            this.sortpan = sortpan;

        }

        @Override
        public Boolean doInBackground() {


            return true;
        }

        @Override
        public void process(java.util.List<Runnable> gui_updates) {

        }

        @Override
        public void done() {

            decWorkerThreads();
        }


    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Jay
  • 520
  • 2
  • 9
  • 23
  • What exactly is your problem? What prevents you from re-starting the sorting? – Alex Abdugafarov Oct 11 '11 at 05:09
  • There is no problem at all. The code executes fine, but I want it to restart once it has finished sorting, i.e. all my buttons need to be set to true. Wait ill post my whole code up. – Jay Oct 11 '11 at 05:12
  • @Jay I tried code that you posted here, so nice ouuput, excelent idea, implements SwingWorker#cancel(), and for JPanels layout look for CardLayout +1 – mKorbel Oct 11 '11 at 07:16
  • @mKorbel - Thanks =D I ma take the code off soon – Jay Oct 11 '11 at 08:02
  • 1) fix Bacgroung Taks, you have to know in every moment how many Threads runs, 2) play with coloring of the Borders for Column that will be changed 3) on the ends fix GUI, because this is not built correctly – mKorbel Oct 11 '11 at 08:36
  • `import java.lang.*;`?? Isn't that kind of unnecessary? Just saying. – fireshadow52 Oct 11 '11 at 22:28
  • @fireshadow52 - Yes, I ma use it later in the code. but I still cant figure out the method mKorbel said. – Jay Oct 12 '11 at 00:25
  • this looks exactly like an assignment I'm currently doing, same comments and everything. I'm going to guess that you're in my class. don't ask people how to do your assignments –  Oct 19 '11 at 03:09

1 Answers1

1

not directly the answers to your question, but there I see three areas, I think that your code missed

notice please read How to get Exception from SwingWorker

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • I have not finished the code yet, thats why it is missing some parts. – Jay Oct 11 '11 at 08:02
  • 1
    @Jay :-) after fixing, please distribute your idea to the some JavaExampleDepots :-) because in current form has this code very nice and with funny output to the screen – mKorbel Oct 11 '11 at 08:23
  • yeah dw thats if I finish it in a week or i ma just leave it – Jay Oct 11 '11 at 08:41