1

私のアルゴリズム クラスの課題は、配列に対してマージソートを実行し、何が起こっているかをアニメーションとして表示することです。コードは (理論的には) 動作していますが、(配列をアニメーション化するために) repaint() を何度もすばやく呼び出すと、それらは無視されます。アニメーションは表示されず、最終的な配列のみが表示されます。コンソールでは、すべての「 * 」の後に「-」が 1 つあるはずですが、そうではありません。「 * 」はたくさんありますが (そうあるべきです)、「-」は 1 つしかありません。' * ' は repaint メソッドが呼び出されるタイミングを示し、'-' は実際に呼び出されるタイミングを示します。

package a2;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class GraphicalSort extends JFrame implements ActionListener {
    int[] data = new int[200];
    int[] helper = new int[200];
    JPanel panel = new JPanel(); //Panel to hold graphical display of array
    JPanel buttonsPanel = new JPanel();
    JButton mButton = new JButton("Mergesort");
    JButton sButton = new JButton("Scramble");

    //Constants to scale the width and height
    int barWidth = 8;
    int barHeight = 1;

    public GraphicalSort() {
        setLayout(new BorderLayout());
        mButton.addActionListener(this);
        sButton.addActionListener(this);
        buttonsPanel.add(sButton);
        buttonsPanel.add(mButton);
        for (int i = 0; i < data.length; i++) {
            data[i] = (int) (500 * Math.random() + 1);
            helper[i] = data[i];
        }
        setSize(barWidth * data.length, barHeight * 500 + buttonsPanel.getHeight());
        panel = new ArrayPanel();
        add(buttonsPanel, BorderLayout.NORTH);
        add(panel, BorderLayout.CENTER);

        repaint();
        validate();
    }

    public static void main(String[] args) {
        GraphicalSort gs = new GraphicalSort();
        gs.setTitle("Graphical Sort");
        gs.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        gs.setLocationRelativeTo(null);
        gs.setResizable(false);
        gs.setVisible(true);
    }

    @SuppressWarnings("serial")
    class ArrayPanel extends JPanel {
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLACK);
            System.out.println("-"); //when repaint is actually called
            int xPos = 0;
            for (int i = 0; i < data.length; i++) {
                g.fillRect(xPos, (barHeight * 500) - (barHeight * data[i]), barWidth, barHeight * data[i]);
                xPos += barWidth;
            }   
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == mButton) {
            mergesort(0, data.length - 1);
        } else if (e.getSource() == sButton) {
            Random r = new Random();
            for (int i = 0; i < data.length; i++) {
                int index = r.nextInt(data.length);
                int temp = data[i];
                data[i] = data[index];
                data[index] = temp;
                panel.repaint();
            }
        }
    }

    private void mergesort(int low, int high)  {
        // Check if low is smaller then high, if not then the array is sorted
        if (low < high) {
            // Get the index of the element which is in the middle
            int middle = (low + high) / 2;
            // Sort the left side of the array
            mergesort(low, middle);
            // Sort the right side of the array
            mergesort(middle + 1, high);
            // Combine them both
            merge(low, middle, high);
            System.out.println("*"); //When the repaint should be called
            panel.repaint();
        }
    }

    private void merge(int low, int middle, int high) {

        // Copy both parts into the helper array
        for (int i = low; i <= high; i++) {
            helper[i] = data[i];
        }       

        int i = low;
        int j = middle + 1;
        int k = low;
        // Copy the smallest values from either the left or the right side back
        // to the original array
        while (i <= middle && j <= high) {
            if (helper[i] <= helper[j]) {
                data[k] = helper[i];
                i++;
            } else {
                data[k] = helper[j];
                j++;
            }
            k++;
        }
        // Copy the rest of the left side of the array into the target array
        while (i <= middle) {
            data[k] = helper[i];
            k++;
            i++;
        }

    }
}    
4

2 に答える 2

1

マージの並べ替えは思ったよりも速く行われ、再描画は非常に接近して呼び出されているため、「スタック」されており、これが発生すると、はい、無視される可能性があります。それらが無視されていない場合でも、コードの速度によって GUI に目に見える変化が生じることはありません。また、処理に時間がかかったとしても、Swing イベント スレッドがあまりにも高速であるため、GUI はロックされます。絵を描くのに忙しい。

解決策は、コードを遅くすることですがThread.sleep(...)、バックグラウンド スレッドではなく Swing タイマーで呼び出された場合に Swing イベント スレッドを再び拘束することはありません。これにより、コードはゆっくりと段階的に進行しますが、Swing イベント スレッドを拘束することはありません。

于 2013-03-28T01:58:45.727 に答える
0

「スクランブル」中にアニメーションを表示するには、アクションの実行済みメソッドを次のように置き換えることができます。必要に応じて、一度に 1 つのスクランブルにスクランブルを制限するコードを追加します。

public void actionPerformed(final ActionEvent e) {
    if (e.getSource() == mButton) {
        mergesort(0, data.length - 1);
    } else if (e.getSource() == sButton) {
        new Thread(new Runnable() {
            public void run() {
                final Random r = new Random();
                for (int i = 0; i < data.length; i++) {
                    try {Thread.sleep(10);} 
                    catch (final InterruptedException e) 
                    { e.printStackTrace(); }
                    final int index = r.nextInt(data.length);
                    final int temp = data[i];
                    data[i] = data[index];
                    data[index] = temp;
                    panel.repaint();
                }
            }
        }).start();
    }
}
于 2013-03-28T02:43:03.057 に答える