2

さて、ソートアルゴリズムがどのように機能するかを示すこのコードにしばらく取り組んできました。現在、複数のグラフを同じソートでソートする場所で動作していますが、各グラフで同時に異なるソートを行う必要があります。私はこれを何日も研究し、解決しようとしてきましたが、今では視野が狭くなっています。説明がわかりにくい場合に備えて、コードを投稿します。これは、Java グラフィックスを扱っている多くの人々に利益をもたらす可能性があると思います。

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Scanner;


public class Sort extends Applet {

/** Constructor. Only for starting the sorting animation as applet. */
public Sort() {}


/** For starting the sorting animation as application. */
public static void main(String[] argv) {
    Frame _aFrame = new Frame("Sort Animations");
    _aFrame.setBackground(Color.white);
    _aFrame.setPreferredSize(new Dimension(2700,1000)); 

    Scanner in = new Scanner(System.in);
    int sizeOfArray;
    System.out.println("How many numbers do you want to sort?");
    sizeOfArray = in.nextInt();


    _aFrame.addWindowListener(
                              new WindowAdapter() {
        public void windowClosing(WindowEvent e) { System.exit(0); }
    }
                              );

    _aFrame.setLayout(new BorderLayout());
    _aFrame.add(new SortPanel(sizeOfArray));
    _aFrame.pack();
    _aFrame.setVisible(true);
}

}



class SortPanel extends Panel implements Runnable {

/** button triggering the sort animation */
private Button aSortButton_    = new Button("sort");
/** choice item for selecting the sort algorithm */
private Choice aChoice_ = new Choice();
/** component for handling the animation */
private ArrayCanvas anArrayCanvas_;


/////////////////////////////////////////////////////////////////////////////

/**
 * Constructor.
 *
 * @param length    no of elements of the array
 * @param aBarColor the color the elements representing bars will be drawn in
 *
 * @exception IllegalArgumentException if the array <code>length</code> is
 *            to big to display (ie <code>length</code> is bigger than
 *            <code>BAR_WIDTH</code> or <code>BAR_HEIGHT</code>).
 */
public SortPanel(int arraySize) {
    setLayout(new BorderLayout());


    aSortButton_.addActionListener(
                new     ActionListener() {
        public void actionPerformed(ActionEvent e) {
            new Thread(SortPanel.this).start();
        }
    }
                );


    anArrayCanvas_ = new ArrayCanvas(arraySize);
    for (int i=0; i<ArrayCanvas.SORT_NAMES.length; ++i)
        aChoice_.add(ArrayCanvas.SORT_NAMES[i]);

    // add buttons at top:
    Panel _aTopPanel = new Panel();
    _aTopPanel.add(aSortButton_);
    add(_aTopPanel, BorderLayout.NORTH);

    // add choice and ArrayCanvas below:
    Panel _aPanel = new Panel();
    _aPanel.setLayout(new BorderLayout());
    Panel _aChoicePanel = new Panel();
    _aChoicePanel.add(aChoice_);
    _aPanel.add(_aChoicePanel, BorderLayout.NORTH);
    _aPanel.add(anArrayCanvas_, BorderLayout.CENTER);

    add(_aPanel, BorderLayout.CENTER);

    Panel _aBottomPanel = new Panel();
    add(_aBottomPanel, BorderLayout.SOUTH);
}

/////////////////////////////////////////////////////////////////////////////

/** Runs the sorting animation. */
public void run() {
    aSortButton_.setEnabled(false);
    double time = System.currentTimeMillis();
    anArrayCanvas_.sort(aChoice_.getSelectedItem());
    aSortButton_.setEnabled(true);
}
}

class ArrayCanvas extends Canvas {

/** Labels of available sorting algorithms. */
public final static String[] SORT_NAMES = { "bubble sort", "insertion sort", "shell  sort", "heap sort", "merge sort", "quick sort",};

/** offset between bars and border in x-directions (left and right) */
public final static int OFFSET_X         = 5;
/** offset between bars and border in y-directions (top and bottom) */
public final static int OFFSET_Y         = 5;
/** horizontal size of all bars together */
public final static int BAR_WIDTH        = 350;
/** (max) vertical horizontal size of bars together */
public final static int BAR_HEIGHT       = 250;
/** milliseconds to sleep after a swap in the sorting animation */
public final static int SLEEP_AFTER_SWAP = 20;

/** used for random permutation of the array elements */
private static Random aRandom_ = new Random(System.currentTimeMillis());
/** the array to display */
private int[] anArrayOfInt_;
/** offscreen buffer */
private Image image_;
/** graphics of the offscreen buffer */
private Graphics offscreenGraphics_;




/////////////////////////////////////////////////////////////////////////////

/**
 * Constructor.
 *
 * @param length    no of elements of the array
 *
 * @exception IllegalArgumentException if the array <code>length</code> is
 *            to big to display (ie <code>length</code> is bigger than
 *            <code>BAR_WIDTH</code> or <code>BAR_HEIGHT</code>).
 */
public ArrayCanvas(int length) {
    if (length > BAR_WIDTH || length > BAR_HEIGHT)
        throw new IllegalArgumentException("array to big: "+length);
    anArrayOfInt_ = new int[length];
    for (int i=0; i<length; ++i)
        anArrayOfInt_[i] = i+1;
    permute();
    addMouseListener(
                     new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
            repaint();
        }
    }
                     );
}

/////////////////////////////////////////////////////////////////////////////


// overloaded for double buffering
public void update(Graphics aGraphics) {
    paint(aGraphics);
}

/** displays the array */
public void paint(Graphics aGraphics) {
    int _deltaX = 0;
    int w = BAR_WIDTH / anArrayOfInt_.length;
    if (w > 1) {
        --w;
        ++_deltaX;
    }
    int _heightFactor = BAR_HEIGHT / anArrayOfInt_.length;
    if (offscreenGraphics_ == null) {
        image_ = createImage(getSize().width, getSize().height);
        offscreenGraphics_ = image_.getGraphics();
    }

    offscreenGraphics_.setColor(getBackground());
    offscreenGraphics_.fillRect(0, 0, getSize().width-1, getSize().height-1);

    offscreenGraphics_.setColor(Color.black);
    //offscreenGraphics_.drawRect(0, 0, getSize().width-1, getSize().height-1);
    offscreenGraphics_.translate(OFFSET_X, OFFSET_Y);
    for (int i=0; i<anArrayOfInt_.length; ++i) {
        int h = _heightFactor*anArrayOfInt_[i];
        offscreenGraphics_.setColor(Color.blue);
        offscreenGraphics_.fillRect((w+_deltaX)*i, BAR_HEIGHT-h, w, h);
        if(anArrayOfInt_[i]==(i+1)){
            offscreenGraphics_.setColor(Color.red);
            offscreenGraphics_.fillRect((w+_deltaX)*i, BAR_HEIGHT-h, w, _heightFactor);
        }
    }

    offscreenGraphics_.translate(-OFFSET_X, -OFFSET_Y);
    aGraphics.drawImage(image_, 0, 0, this);
    aGraphics.drawImage(image_, 475, 0, this);
    aGraphics.drawImage(image_, 950, 0, this);
    aGraphics.drawImage(image_, 0, 350, this);
    aGraphics.drawImage(image_, 475, 350, this);
    aGraphics.drawImage(image_, 950, 350, this);

}

public Dimension getMinimumSize() {
    return new Dimension(BAR_WIDTH+2*OFFSET_X, BAR_HEIGHT+2*OFFSET_Y);
}

public Dimension getPreferredSize() {
    return getMinimumSize();
}

///////////////////////////////////////////////////

/** random permutation of array entries */
public void permute() {
    for (int i=anArrayOfInt_.length-1; i>0; --i) {
        int j = Math.abs(aRandom_.nextInt()) % (i+1);
        swap(anArrayOfInt_,i,j);
    }
}


/** animated sort */
public void sort(String aSortNameString) {
    mySort(aSortNameString);
}

///////////////////////////////////////////////////


private void mySort(String aSortNameString) {

    if (aSortNameString.equals("bubble sort")) {
        bubbleSort(anArrayOfInt_);

    }

    if (aSortNameString.equals("insertion sort")) {
        insertionSort(anArrayOfInt_);
    }

    if (aSortNameString.equals("selection sort")) {
        selectionSort(anArrayOfInt_);
    }

    if (aSortNameString.equals("shell sort")) {
        shellSort(anArrayOfInt_);

    }
    if (aSortNameString.equals("heap sort")) {
        heapSort(anArrayOfInt_);

    }
    if (aSortNameString.equals("merge sort")) {
        mergeSort(anArrayOfInt_, 0, anArrayOfInt_.length-1);

    }
    if (aSortNameString.equals("quick sort")) {
        qSort(anArrayOfInt_, 0, anArrayOfInt_.length-1);

    }

}

/**
 * swaps the two array elements, redisplays the array in its canvas,
 * and waits a moment.
 */
private void swap(int[] anArrayOfInt, int i, int j) {
    int x = anArrayOfInt[i];
    anArrayOfInt[i] = anArrayOfInt[j];
    anArrayOfInt[j] = x;
    repaint();
    try { Thread.sleep(SLEEP_AFTER_SWAP); } catch (InterruptedException e) {}
}


/////////////////////////////////////////////////////////////////////////////
//                          SORTING ALGORITHMS                             //
/////////////////////////////////////////////////////////////////////////////

/** bubble sort */
private void bubbleSort(int[] anArrayOfInt) {
    for (int i=0; i<anArrayOfInt.length; ++i)
        for (int j=1; j<anArrayOfInt.length-i; ++j)
            if (anArrayOfInt[j-1]>anArrayOfInt[j]) {
                swap(anArrayOfInt, j-1, j);
            }
}



/** insertion sort */
private void insertionSort(int[] anArrayOfInt) {
    for (int i=0; i<anArrayOfInt.length; ++i)
        for (int j=i-1; j>=0 && anArrayOfInt[j]>anArrayOfInt[j+1]; --j)
            swap(anArrayOfInt, j, j+1);
}


/** selection sort */
private void selectionSort(int[] anArrayOfInt) {
    for (int i=0; i<anArrayOfInt.length-1; ++i) {
        for (int j=i+1; j<anArrayOfInt.length; ++j)
            if (anArrayOfInt[j] < anArrayOfInt[i])
                swap(anArrayOfInt, i, j);
    }
}

/** shell sort */
private void shellSort(int[] anArrayOfInt) {
    // TODO: calculate needed STEPS-elements instead of using an array
    //       (STEPS[i+1] = 3*STEPS[i]+1)
    for (int i=0; i<STEPS.length; ++i) {
        int _delta = STEPS[i];
        if (_delta >= anArrayOfInt.length)
            continue;
        for (int j=_delta; j<anArrayOfInt.length; ++j)
            for (int k=j; k-_delta>=0 && anArrayOfInt[k]<anArrayOfInt[k-  _delta];
                 k-=_delta)
                swap(anArrayOfInt, k, k-_delta);
    }
}

/** used by shell sort */
private final static int[] STEPS = { 1093, 364, 121, 40, 13, 4, 1 };

/** heap sort */
private void heapSort(int[] anArrayOfInt) {
    int r = anArrayOfInt.length-1;
    for (int l = anArrayOfInt.length/2 ; l>=0; --l)
        sift(anArrayOfInt, l, r);
    while (r > 0) {
        swap(anArrayOfInt, 0, r);
        sift(anArrayOfInt, 0, --r);
    }
}

/** auxiliary function for heap sort. */
private void sift(int[] anArrayOfInt, int l, int r) {
    if (r==l)
        return;
    int i = l, j = 2*l;
    int x = anArrayOfInt[i];
    if (j<r && anArrayOfInt[j]<anArrayOfInt[j+1])
        ++j;
    while (j<=r && x<=anArrayOfInt[j]) {
        swap(anArrayOfInt, i, j);
        i = j; j = 2*j;
        if (j<r && anArrayOfInt[j]<anArrayOfInt[j+1])
            ++j;
    }
}

/** quick sort (pivot=(l+r)/2)*/
private void qSort(int[] anArrayOfInt, int l, int r) {
    if (l >= r)
        return;
    swap(anArrayOfInt, l, (l+r)/2); // TODO: more clever pivot
    int _last = l;
    for (int i=l+1; i<=r; ++i)
        if (anArrayOfInt[i] < anArrayOfInt[l])
            swap(anArrayOfInt, ++_last, i);
    swap(anArrayOfInt, l, _last);
    qSort(anArrayOfInt, l, _last-1);
    qSort(anArrayOfInt, _last+1, r);
}


/** merge sort */
private void mergeSort(int[] anArrayOfInt, int l, int r) {
    int[][] B = new int[2][r+1];
    mergeSort16(anArrayOfInt, B, l, r);
}

private void mergeSort16(int[] anArrayOfInt, int[][] B, int l, int r) {
    if (l >= r)
        return;
    int _last = (l+r)/2;
    mergeSort16(anArrayOfInt, B, l, _last);
    mergeSort16(anArrayOfInt, B, _last+1, r);
    merge6(anArrayOfInt, B, l, _last, r);
}
/** auxiliary function for merge sort */
protected void merge6(int[] anArrayOfInt, int[][] B, int l, int q, int r) {
    for (int i=l;i<=q;i++) {
        B[0][i] = i;
        B[1][i] = i;
    }
    for (int i=r;i>q;i--) {
        B[0][i] = r+q+1-i;
        B[1][i] = r+q+1-i;
    }
    int i = l;
    int j = r;
    for (int k=l; k<r;k++) {
        int s = B[0][i];
        int t = B[0][j];
        if (anArrayOfInt[s]<=anArrayOfInt[t]) {
            i++;
        } else {
            s = t;
            j--;
        }
        swap(anArrayOfInt, s, k);
        t = B[1][k];
        B[0][t] = s;
        B[1][s] = t;
    }
}

}
4

1 に答える 1

8

ソートグラフごとに、各ソートの現在の状態を保持するモデルが必要です。これはおそらく、のリストをintソートごとに別のリストに追加することを意味します。

また、各ソートアルゴリズムをループして、そのアルゴリズムの次のステップに移動するように指示できるメカニズムも必要です。これにより、各ソートアルゴリズムが更新されるタイミングを制御できるため、画面が更新されるタイミングを制御できます。

更新しました

OPからのコメントに基づいて、基本的に、ソートアルゴリズムを別のインターフェースとして取り除きました。各アルゴリズムはこのインターフェイスから拡張する必要がありますが、UI が並べ替えアニメーションをレンダリングできるようにするための基本的な要件を提供します。

以下は基本的な実装ですが、Swing に基づいていますが、必要に応じて AWT で動作させるのは難しくありません。

ここに画像の説明を入力

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class TestSort {

    public static void main(String[] args) {
        new TestSort();
    }

    public TestSort() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                SortPane sortPane = new SortPane();
                int values[] = new int[10];
                for (int index = 0; index < values.length; index++) {
                    values[index] = (int)Math.round(Math.random() * 100f);
                }
                BubbleSort sorter = new BubbleSort(values);
                sortPane.setSorter(sorter);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(sortPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                sorter.sort();
            }
        });
    }

    public class SortPane extends JPanel {

        private Sorter sorter;
        private ChangeHandler changeHandler;
        private int maxValue;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int values[] = getSorter().getValues();
            int width = getWidth() - 1;
            int height = getHeight() - 1;
            int colWidth = Math.round((float)width / (float)values.length);
            int x = 0;
            Color fill = Color.YELLOW;
            Color highlight = null;
            switch (getSorter().getState()) {
                case Sorting:
                    fill = Color.BLUE;
                    highlight = Color.RED;
                    break;
                case Done:
                    fill = Color.GREEN;
                    break;
            }
            for (int index = 0; index < values.length; index++) {
                g2d.setColor(fill);
                int value = values[index];
                int colHeight = (int)((float)height * ((float)value / (float)maxValue));
                g2d.fillRect(x, height - colHeight, colWidth - 1, colHeight);
                if (getSorter().isActiveIndex(index) && highlight != null) {
                    g2d.setColor(highlight);
                    g2d.drawRect(x, height - colHeight, colWidth - 1, colHeight);
                }
                x += colWidth;
            }
            g2d.dispose();
        }

        public Sorter getSorter() {
            return sorter;
        }

        public void setSorter(Sorter value) {
            if (sorter != value) {
                if (sorter != null) {
                    sorter.removeChangeListener(getChangeHandler());
                }
                sorter = value;
                if (sorter != null) {
                    sorter.addChangeListener(getChangeHandler());
                    maxValue = 0;
                    for (int intValue : sorter.getValues()) {
                        maxValue = Math.max(maxValue, intValue);
                    }
                }
                repaint();
            }
        }

        public ChangeHandler getChangeHandler() {
            if (changeHandler == null) {
                changeHandler = new ChangeHandler();
            }
            return changeHandler;
        }

        public class ChangeHandler implements ChangeListener {
            @Override
            public void stateChanged(ChangeEvent e) {
                repaint();
            }
        }

    }

    public interface Sorter {

        public enum State {
            Waiting,
            Sorting,
            Done
        }

        public void addChangeListener(ChangeListener listener);
        public void removeChangeListener(ChangeListener listener);
        public int[] getValues();
        public void sort();
        public State getState();
        public boolean isActiveIndex(int index);
    }

    public abstract class AbstracSorter implements Sorter {

        private List<ChangeListener> listeners;
        private int[] values;
        private State state = State.Waiting;
        private List<Integer> activeIndices;

        public AbstracSorter(int[] values) {
            this.values = values;
            listeners = new ArrayList<>(25);
            activeIndices = new ArrayList<>(2);
        }

        @Override
        public State getState() {
            return state;
        }

        public void setState(State value) {
            if (value != state) {
                state = value;
                fireStateChanged();
            }
        }

        @Override
        public int[] getValues() {
            return values;
        }

        @Override
        public void addChangeListener(ChangeListener listener) {
            listeners.add(listener);
        }

        @Override
        public void removeChangeListener(ChangeListener listener) {
            listeners.remove(listener);
        }

        protected void fireStateChanged() {
            if (listeners.size() > 0) {
                ChangeEvent evt = new ChangeEvent(this);
                for (ChangeListener listener : listeners) {
                    listener.stateChanged(evt);
                }
            }
        }

        @Override
        public boolean isActiveIndex(int index) {
            return activeIndices.contains(index);
        }

        protected void setActiveIndicies(int lower, int upper) {
            activeIndices.clear();
            activeIndices.add(lower);
            activeIndices.add(upper);
            fireStateChanged();
        }

        protected void swap(int[] anArrayOfInt, int i, int j) {
            setActiveIndicies(i, j);
            int x = anArrayOfInt[i];
            anArrayOfInt[i] = anArrayOfInt[j];
            anArrayOfInt[j] = x;
            fireStateChanged();
        }
    }

    public class BubbleSort extends AbstracSorter {

        private int outter = 0;
        private int inner = 0;

        public BubbleSort(int[] values) {
            super(values);
        }

        @Override
        public void sort() {
            setState(State.Sorting);
            outter = 0;
            inner = 1;
            Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    int[] values = getValues();
                    inner++;
                    if (inner >= values.length - outter) {
                        outter++;
                        inner = 1;
                    }

                    if (outter < values.length) {
                        if (values[inner - 1] > values[inner]) {
                            swap(values, inner - 1, inner);
                        } else {
                            setActiveIndicies(inner - 1, inner);
                        }
                    } else {
                        ((Timer)e.getSource()).stop();
                        setState(State.Done);
                    }
                }
            });
            timer.setRepeats(true);
            timer.start();
        }
    }
}

ソース配列を使用した例

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class TestSort {

    public static void main(String[] args) {
        new TestSort();
    }
    private List<Sorter> sorters;

    public TestSort() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                sorters = new ArrayList<>(2);
                int values[] = new int[10];
                for (int index = 0; index < values.length; index++) {
                    values[index] = (int) Math.round(Math.random() * 100f);
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridLayout(0, 2));
                frame.add(createBubbleSortPane(values));
                frame.add(createBubbleSortPane(values));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                for (Sorter sorter : sorters) {
                    sorter.sort();
                }
            }
        });
    }

    protected SortPane createBubbleSortPane(int[] values) {
        SortPane sortPane = new SortPane();
        BubbleSort sorter = new BubbleSort(values);
        sortPane.setSorter(sorter);

        sortPane.setBorder(new CompoundBorder(new LineBorder(Color.GRAY), new EmptyBorder(8, 8, 8, 8)));

        sorters.add(sorter);

        return sortPane;
    }

    public class SortPane extends JPanel {

        private Sorter sorter;
        private ChangeHandler changeHandler;
        private int maxValue;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int values[] = getSorter().getValues();
            Insets insets = getInsets();
            int width = getWidth() - 1 - (insets.left + insets.right);
            int height = getHeight() - 1 - (insets.top + insets.bottom);
            int colWidth = Math.round((float) width / (float) values.length);
            int x = insets.left;
            Color fill = Color.YELLOW;
            Color highlight = null;
            switch (getSorter().getState()) {
                case Sorting:
                    fill = Color.BLUE;
                    highlight = Color.RED;
                    break;
                case Done:
                    fill = Color.GREEN;
                    break;
            }
            for (int index = 0; index < values.length; index++) {
                g2d.setColor(fill);
                int value = values[index];
                int colHeight = (int) ((float) height * ((float) value / (float) maxValue));
                g2d.fillRect(x, insets.top + height - colHeight, colWidth - 1, colHeight);
                if (getSorter().isActiveIndex(index) && highlight != null) {
                    g2d.setColor(highlight);
                    g2d.drawRect(x, insets.top + height - colHeight, colWidth - 1, colHeight);
                }
                x += colWidth;
            }
            g2d.dispose();
        }

        public Sorter getSorter() {
            return sorter;
        }

        public void setSorter(Sorter value) {
            if (sorter != value) {
                if (sorter != null) {
                    sorter.removeChangeListener(getChangeHandler());
                }
                sorter = value;
                if (sorter != null) {
                    sorter.addChangeListener(getChangeHandler());
                    maxValue = 0;
                    for (int intValue : sorter.getValues()) {
                        maxValue = Math.max(maxValue, intValue);
                    }
                }
                repaint();
            }
        }

        public ChangeHandler getChangeHandler() {
            if (changeHandler == null) {
                changeHandler = new ChangeHandler();
            }
            return changeHandler;
        }

        public class ChangeHandler implements ChangeListener {

            @Override
            public void stateChanged(ChangeEvent e) {
                repaint();
            }
        }
    }

    public interface Sorter {

        public enum State {

            Waiting,
            Sorting,
            Done
        }

        public void addChangeListener(ChangeListener listener);

        public void removeChangeListener(ChangeListener listener);

        public int[] getValues();

        public void sort();

        public State getState();

        public boolean isActiveIndex(int index);
    }

    public abstract class AbstracSorter implements Sorter {

        private List<ChangeListener> listeners;
        private int[] values;
        private State state = State.Waiting;
        private List<Integer> activeIndices;

        public AbstracSorter(int[] values) {
            this.values = new int[values.length];
            System.arraycopy(values, 0, this.values, 0, values.length);
            listeners = new ArrayList<>(25);
            activeIndices = new ArrayList<>(2);
        }

        @Override
        public State getState() {
            return state;
        }

        public void setState(State value) {
            if (value != state) {
                state = value;
                fireStateChanged();
            }
        }

        @Override
        public int[] getValues() {
            return values;
        }

        @Override
        public void addChangeListener(ChangeListener listener) {
            listeners.add(listener);
        }

        @Override
        public void removeChangeListener(ChangeListener listener) {
            listeners.remove(listener);
        }

        protected void fireStateChanged() {
            if (listeners.size() > 0) {
                ChangeEvent evt = new ChangeEvent(this);
                for (ChangeListener listener : listeners) {
                    listener.stateChanged(evt);
                }
            }
        }

        @Override
        public boolean isActiveIndex(int index) {
            return activeIndices.contains(index);
        }

        protected void setActiveIndicies(int lower, int upper) {
            activeIndices.clear();
            activeIndices.add(lower);
            activeIndices.add(upper);
            fireStateChanged();
        }

        protected void swap(int[] anArrayOfInt, int i, int j) {
            setActiveIndicies(i, j);
            int x = anArrayOfInt[i];
            anArrayOfInt[i] = anArrayOfInt[j];
            anArrayOfInt[j] = x;
            fireStateChanged();
        }
    }

    public class BubbleSort extends AbstracSorter {

        private int outter = 0;
        private int inner = 0;

        public BubbleSort(int[] values) {
            super(values);
        }

        @Override
        public void sort() {
            setState(State.Sorting);
            outter = 0;
            inner = 1;
            Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    int[] values = getValues();
                    inner++;
                    if (inner >= values.length - outter) {
                        outter++;
                        inner = 1;
                    }

                    if (outter < values.length) {
                        if (values[inner - 1] > values[inner]) {
                            swap(values, inner - 1, inner);
                        } else {
                            setActiveIndicies(inner - 1, inner);
                        }
                    } else {
                        ((Timer) e.getSource()).stop();
                        setState(State.Done);
                    }
                }
            });
            timer.setRepeats(true);
            timer.start();
        }
    }
}

挿入ソーターの例

Threadこれは、Swing の代わりに をプライマリ ソート エンジンとして使用する例です。Timer

public class InsertionSorter extends AbstracSorter {

    public InsertionSorter(int[] values) {
        super(values);
    }

    @Override
    public void sort() {
        setState(State.Sorting);
        new Thread(new SortRunnable()).start();
    }

    @Override
    protected void swap(int[] anArrayOfInt, int i, int j) {
        setActiveIndicies(i, j);
        int x = anArrayOfInt[i];
        anArrayOfInt[i] = anArrayOfInt[j];
        anArrayOfInt[j] = x;
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                @Override
                public void run() {
                    fireStateChanged();
                }
            });
        } catch (InterruptedException | InvocationTargetException exp) {
            exp.printStackTrace();
        }
    }

    public class SortRunnable implements Runnable {

        @Override
        public void run() {
            int[] values = getValues();
            for (int i = 0; i < values.length; ++i) {
                for (int j = i - 1; j >= 0 && values[j] > values[j + 1]; --j) {
                    try {
                        Thread.sleep(250);
                    } catch (InterruptedException ex) {
                    }
                    swap(values, j, j + 1);
                }
            }
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    setState(State.Done);
                }
            });
        }
    }
}
于 2013-04-02T04:50:33.470 に答える