Bubble sort animation

后端 未结 2 919
Happy的楠姐
Happy的楠姐 2021-01-16 21:27

Lately I\'ve noticed questions asking about animation of code that uses a looping algorithm. For example:

  1. Java: How to use swing timer for delaying actions
相关标签:
2条回答
  • 2021-01-16 21:56

    Another approach might be to use a SwingWorker.

    The SwingWorker creates runs in its own Thread and allows you to "publish" intermittent results to be painted.

    The key to the approach below is that a copy of the data is passed to the SwingWorker. This allows the worker to sort the data while the data is being repainted so you don't have to worry about the data in the array being in an inconsistent state.

    After each iteration of the looping code the new state of the array is updated so it can be painted.

    This allows you to easily move the sorting logic into the SwingWorker without refactoring.

    import java.awt.*;
    import java.awt.event.*;
    import java.util.Arrays;
    import java.util.List;
    import javax.swing.*;
    import javax.swing.Timer;
    
    public class BubbleSortWorker extends JPanel
    {
        private final static int BAR_WIDTH = 30;
        private final static int BAR_HEIGHT_MAX = 400;
    
        private int[]items;
    
        public BubbleSortWorker(int[] items)
        {
            this.items = items;
        }
    
        public void setItems(int[] items)
        {
            this.items = items;
            repaint();
        }
    
        public void sort()
        {
            new SortWorker(items).execute();
        }
    
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
    
            for (int i = 0; i < items.length; i++)
            {
                int x = i * BAR_WIDTH;
                int y = getHeight() - items[i];
    
                g.setColor( Color.RED );
                g.fillRect(x, y, BAR_WIDTH, items[i]);
    
                g.setColor( Color.BLUE );
                g.drawString("" + items[i], x, y);
            }
        }
    
        @Override
        public Dimension getPreferredSize()
        {
            return new Dimension(items.length * BAR_WIDTH, BAR_HEIGHT_MAX + 20);
        }
    
        class SortWorker extends SwingWorker<Void, int[]>
        {
            private int[] items;
    
            public SortWorker(int[] unsortedItems)
            {
                items = Arrays.copyOf(unsortedItems, unsortedItems.length);
            }
    
            @Override
            protected Void doInBackground()
            {
                int n = items.length;
                int temp = 0;
    
                for (int i = 0; i < n; i++)
                {
                    for (int j = 1; j < (n - i); j++)
                    {
                        if (items[j-1] > items[j])
                        {
                            temp = items[j - 1];
                            items[j - 1] = items[j];
                            items[j] = temp;
    
                            //repaint();
                            publish( Arrays.copyOf(items, items.length) );
    
                            try { Thread.sleep(100); } catch (Exception e) {}
                        }
                    }
                }
    
                return null;
            }
    
            @Override
            protected void process(List<int[]> list)
            {
                int[] items = list.get(list.size() - 1);
                setItems( items );
            }
    
            @Override
            protected void done() {}
        }
    
        public static int[]generateRandomNumbers()
        {
            int[] items = new int[10];
    
            for(int i = 0; i < items.length; i++)
            {
                items[i] = (int)(Math.random() * BubbleSortWorker.BAR_HEIGHT_MAX);
            }
    
            return items;
        }
    
        private static void createAndShowGUI()
        {
            BubbleSortWorker bubbleSort = new BubbleSortWorker( BubbleSortWorker.generateRandomNumbers() );
    
            JButton generate = new JButton("Generate Data");
            generate.addActionListener((e) -> bubbleSort.setItems( BubbleSortWorker.generateRandomNumbers() ) );
    
            JButton sort = new JButton("Sort Data");
            sort.addActionListener((e) -> bubbleSort.sort());
    
            JPanel bottom = new JPanel();
            bottom.add( generate );
            bottom.add( sort );
    
            JFrame frame = new JFrame("SSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(bubbleSort, BorderLayout.CENTER);
            frame.add(bottom, BorderLayout.PAGE_END);
            frame.pack();
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
    
        public static void main(String[] args) throws Exception
        {
            EventQueue.invokeLater( () -> createAndShowGUI() );
        }
    }
    
    0 讨论(0)
  • 2021-01-16 22:07

    A Swing Timer works on event driven code. Therefore the iterative code must be refactored to event driven code.

    Some things to consider during this process:

    1. state must be added to the algorithm. This means that all local variables used to control the looping algorithm must be converted to instance variables of the class.

    2. the looping algorithm must be split into two methods, the first to set the initial state of the algorithm and start the timer, and the second method to update the state and stop the Timer.

    Using the above suggestion the refactoring of your code might be something like:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class BubbleSortTimer extends JPanel
    {
        private final static int BAR_WIDTH = 30;
        private final static int BAR_HEIGHT_MAX = 400;
    
        private int[]items;
        private int i, j, n;
        private Timer timer;
    
        public BubbleSortTimer(int[] items)
        {
            this.items = items;
    
            timer = new Timer(100, (e) -> nextIteration());
        }
    
        public void setItems(int[] items)
        {
            this.items = items;
            repaint();
        }
    
        public void sort()
        {
            i = 0;
            j = 1;
            n = items.length;
    
            timer.start();
        }
    
        public void nextIteration()
        {
            if (items[j - 1] > items[j])
            {
                int temp = items[j - 1];
                items[j - 1] = items[j];
                items[j] = temp;
    
                repaint();
            }
    
            j++;
    
            if (j >= n - i)
            {
                j = 1;
                i++;
            }
    
            if (i == n)
                timer.stop();
        }
    
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
    
            for (int i = 0; i < items.length; i++)
            {
                int x = i * BAR_WIDTH;
                int y = getHeight() - items[i];
    
                g.setColor( Color.RED );
                g.fillRect(x, y, BAR_WIDTH, items[i]);
    
                g.setColor( Color.BLUE );
                g.drawString("" + items[i], x, y);
            }
        }
    
        @Override
        public Dimension getPreferredSize()
        {
            return new Dimension(items.length * BAR_WIDTH, BAR_HEIGHT_MAX + 20);
        }
    
        public static int[]generateRandomNumbers()
        {
            int[] items = new int[10];
    
            for(int i = 0; i < items.length; i++)
            {
                items[i] = (int)(Math.random() * BubbleSortTimer.BAR_HEIGHT_MAX);
            }
    
            return items;
        }
    
        private static void createAndShowGUI()
        {
            BubbleSortTimer bubbleSort = new BubbleSortTimer( BubbleSortTimer.generateRandomNumbers() );
    
            JButton generate = new JButton("Generate Data");
            generate.addActionListener((e) -> bubbleSort.setItems( BubbleSortTimer.generateRandomNumbers() ) );
    
            JButton sort = new JButton("Sort Data");
            sort.addActionListener((e) -> bubbleSort.sort());
    
            JPanel bottom = new JPanel();
            bottom.add( generate );
            bottom.add( sort );
    
            JFrame frame = new JFrame("SSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(bubbleSort, BorderLayout.CENTER);
            frame.add(bottom, BorderLayout.PAGE_END);
            frame.pack();
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
    
        public static void main(String[] args) throws Exception
        {
            EventQueue.invokeLater( () -> createAndShowGUI() );
        }
    }
    
    0 讨论(0)
提交回复
热议问题