Zrobiłem to dla mojego bachelorthesis, zrobiłem to tak (to nie jest idealne, ale może ci pomóc).
(usunąłem kilka nieistotnych metod/funkcji z poniższym kodzie To głównie do zilustrowania tego, jak ją zwizualizowałem.Możesz zastąpić klasę GRectangle na przykład za pomocą prostego pliku java.awt.Point).
Metoda inicjalizacji daje przykład, jak znaleźć maksymalną i minimalną wartość danych więc wiesz, jak przekształcać współrzędne danych =>.
public class DotVisualisation extends Visualisation {
private ArrayList<GRectangle> m_points;
private Comparable[] m_data;
private Comparable m_maxValue;
private Comparable m_minValue;
private int MAX_HEIGHT; // max height in pixels of visualization
/**
* Creates a new DotVisualisation.<br>
* <br>
* This class is a runnable JComponent that will visualize data as a function.
* The visualisation will plot the data with X and Y coordinates on the window.
* The X coordinate of the point is index of the dataelement.
* The Y coordinate of the point is relative to the value of the dataelement.<br>
* <br>
* This visualisation should be used for medium and large arrays.
*
* @author David Nysten
*/
public DotVisualisation()
{
m_points = new ArrayList<GRectangle>();
MAX_HEIGHT = 150;
}
/**
* Returns the maximum supported dimension by this visualisation.
*
* @return The supported dimension.
*/
public static int getSupportedDimension()
{
return 1;
}
@Override
public Dimension getMaximumSize()
{
return getPreferredSize();
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(m_points.size() + 2, MAX_HEIGHT + 6);
}
@Override
public Dimension getMinimumSize()
{
return getPreferredSize();
}
@Override
public void paintComponent(Graphics g)
{
for(int i = 0; i < m_points.size(); ++i)
m_points.get(i).paintComponent(g);
}
private void swap(int index, int index2) { // See below }
private void initialise()
{
findMinimum();
findMaximum();
m_points.clear();
double multiplier;
int x = 0, y = 0, h;
for(int i = 0; i < m_data.length; ++i)
{
if(m_data[i].compareTo(-1) <= 0)
h = 0;
else
{
Integer value = (Integer) m_data[i];
Integer min = (Integer) m_minValue;
Integer diff = (Integer) m_maxValue - min;
multiplier = MAX_HEIGHT/diff.doubleValue();
h = (int) ((value - min) * multiplier);
}
y = (int) (MAX_HEIGHT - h);
GRectangle r = new GRectangle(x, y, 1, 1); // 1, 1 = width and height
r.setColor(Color.BLACK);
m_points.add(r);
++x;
}
}
private void findMaximum()
{
Comparable max = null;
if(m_data.length > 0)
{
max = m_data[0];
for(int i = 1; i < m_data.length; ++i)
if(m_data[i].compareTo(max) > 0)
max = m_data[i];
}
m_maxValue = max;
}
private void findMinimum()
{
Comparable min = null;
if(m_data.length > 0)
{
min = m_data[0];
for(int i = 1; i < m_data.length; ++i)
if(m_data[i].compareTo(min) < 0)
min = m_data[i];
}
m_minValue = min;
}
}
Weź to pod uwagę: Wizualizacja całkowitymi między 0 a 150 na wysokości 150 pikseli jest bardzo proste. Wizualizacja zbioru liczb całkowitych między wartościami 565 i 3544545 na wysokości 150 jest nieco mniejsza.
PS: Kod używa indeksu elementu na wejściu jako współrzędnej X.
PS: Klasa zachowuje odwołanie do wejścia (zmienna m_data), ale nie jest to potrzebne, potrzebne jest tylko do zainicjowania punktów.
PS: Moja klasa "Wizualizacji", która jest rozszerzona o wszystkie wizualizacje, jest w zasadzie JPanelem.
PS: Powyższy kod jest zapisany dla dodatnich liczb całkowitych, więc prawdopodobnie będzie potrzebował dodatkowego kodowania do obsługi ujemnych liczb całkowitych, jak również;).
Następnie w celu wizualizacji działań algorytmu użyłem wzorca obserwatora. Algorytm, na przykład sortowanie bąbelkowe, wyglądał następująco:
for(int i = 0; i < size(); ++i)
for(int j = 1; j < size(); ++j)
if(greaterThan(j - 1, j))
swap(j - 1, j);
Gdzie swap funkcja została zdefiniowana w następujący sposób (wersja uproszczona znowu):
protected void swap(int index1, int index2)
{
if(index1 != index2)
{
incrementSwap(); // counting swaps and visualizing counter
m_command.clear();
m_command.setAction(Action.SWAP);
m_command.addParameter(index1);
m_command.addParameter(index2);
setChanged();
notifyObservers(m_command);
E temp = m_data[index1];
m_data[index1] = m_data[index2];
m_data[index2] = temp;
}
}
Gdzie ja powiadomiony moich obserwatorów (wizualizacje), że zamiana wystąpił na indeksie 1 i indeksie 2. Zmienna m_command jest instancją klasy Command (sam ją napisałem), która jest jedynie opakowaniem informacji potrzebnych do wizualizacji. To jest: akcja, która miała miejsce, i odpowiednie informacje (np. Wskaźniki dla akcji typu swap).
W wizualizacji zamieniłem GRektangles na te wskaźniki oraz ich współrzędne X;
private void swap(int index, int index2)
{
if(index == index2)
return;
GRectangle r1 = m_points.get(index);
GRectangle r2 = m_points.get(index2);
int tempX = r1.getX();
r1.setLocation(r2.getX(), r1.getY());
r2.setLocation(tempX, r2.getY());
m_points.set(index, r2);
m_points.set(index2, r1);
}
Możesz dodać linie tak:
try {
Thread.sleep(100);
} catch(InterruptedException ignore) {}
do niech 100ms snu nić przed continueing.Może się to przydać, jeśli wizualizacja jest zbyt szybka.
Tak na tablicy z losowych liczb może wyglądać następująco:
i po Sortowanie: (Oczywiście to nie jest prosta, ponieważ wartości w inputarray były generowane losowo w ten przypadek)
Więc jeśli trzeba - jak miałem do - pozwalają wielu algorytmów do pracy z tej samej wizualizacji, mogę RECOM napraw w celu oddzielenia klasy wizualizacji od klasy algorytmu i pracy z wzorcem obserwatora, aby umożliwić aktualizację wizualizacji za każdym razem, gdy nastąpi akcja (ustaw, zamień ...).
A potem możesz stworzyć coś takiego dla porównań;
http://i445.photobucket.com/albums/qq179/ultddave/DotVisualizationMany_zps63269d2a.png http://i445.photobucket.com/albums/qq179/ultddave/DotVisualizationMany2_zps65e96fa9.png
Powodzenia!