1

对于我的算法课,我们的任务是对数组执行合并排序并以动画的形式显示正在发生的事情。我的代码(理论上)可以正常工作,但是当我快速多次调用 repaint() (为数组设置动画)时,它们被忽略了。没有动画显示,只是最后的数组。控制台中的每个“*”之后应该有一个“-”,但事实并非如此,有很多“*”(应该有)但只有一个“-”。' * ' 表示何时应该调用 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 没有可见的变化,即使该过程确实花费了很多时间,GUI 也会被锁定,因为 Swing 事件线程也会被锁定忙着画画。

解决方案是减慢您的代码速度,但Thread.sleep(...)如果不在后台线程中调用,而不是使用 Swing 计时器,则不会再次占用 Swing 事件线程。这将允许代码以较慢的逐步方式进行,但不会占用 Swing 事件线程。

于 2013-03-28T01:58:45.727 回答
0

要在“争夺”期间查看动画,您可以将您的动作执行方法替换为以下内容。可以选择添加代码以将加扰限制为一次一个加扰。

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 回答