Bubble Sort Animation

Bubble sort animation

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;
private boolean everySwap;

public BubbleSortWorker(int[] items, boolean everySwap)
{
this.items = items;
this.everySwap = everySwap;
}

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;

// Update after every swap is done

if (everySwap)
{
publish( Arrays.copyOf(items, items.length) );
try { Thread.sleep(100); } catch (Exception e) {}
}
}
}

// Update once per iteration

if (!everySwap)
{
publish( Arrays.copyOf(items, items.length) );
try { Thread.sleep(500); } 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(), true);

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() );
}
}

Check out Worker Threads and Swing Worker for more information about SwingWorker.

How do I correctly implement a bubble sort algorithm in python tkinter?

Sample Image

The biggest problem is that inside sort_two you have if

if y2 > y1:
canvas.move(pos_0, x_10-x_00, 0)
canvas.move(pos_1, x_01-x_11, 0)

which replaces elements only if y2 > y1

but after sort_two() you use barList

sort_two(pos_1, pos_2)
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]

which always replaces elements on list.

And this way you have wrong results on screen.

You could return True/False from sort_two() to control when to change elements on barList

if y2 > y1:
canvas.move(pos_0, x_10-x_00, 0)
canvas.move(pos_1, x_01-x_11, 0)
return True
else:
return False

and

if sort_two(pos_1, pos_2):
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]

Here finall code

I use simple calculation for replacing elements on canvas

x1, _, _, _ = canvas.coords(pos_0)
x2, _, _, _ = canvas.coords(pos_1)

diff = x1 - x2

canvas.move(pos_0, -diff, 0)
canvas.move(pos_1, +diff, 0)

I also removed

 else:
break

which stop animation after every replace and it needs to click button sort again and again - and I use

    window.update()
time.sleep(0.1)

so it displays animation (slowly) to the end of sorting and I don't have to click button sort

import tkinter as tk
import random
import time

def swap_two_pos(pos_0, pos_1):
"""This does the graphical swapping of the rectangles on the canvas
by moving one rectangle to the location of the other, and vice versa
"""

x1, _, _, _ = canvas.coords(pos_0)
x2, _, _, _ = canvas.coords(pos_1)

diff = x1 - x2

canvas.move(pos_0, -diff, 0)
canvas.move(pos_1, +diff, 0)

def sort_two(pos_0, pos_1):
x1, y1, _, _ = canvas.coords(pos_0)
x2, y2, _, _ = canvas.coords(pos_1)

diff = x1 - x2

# moves each rectangle to the x position of the other; y remains unchanged
if y2 > y1:
canvas.move(pos_0, -diff, 0)
canvas.move(pos_1, +diff, 0)
return True
else:
return False

def rand_sort():
for i in range(50000):
rd1 = random.randint(0, 58)
rd2 = random.randint(0, 58)
pos_1 = barList[rd1]
pos_2 = barList[rd2]
if sort_two(pos_1, pos_2):
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]

def sort ():
n = len(barList)

# Traverse through all array elements
for i in range(n):

# Last i elements are already in place
for j in range(0, n-i-1):
if sort_two(barList[j], barList[j+1]):
barList[j], barList[j+1] = barList[j+1], barList[j]

window.update()
time.sleep(0.1)


def random_swap():
"""Not a sort yet, but you have the bare bones operations
so the swap is executed
"""
for i in range(500):
rd1 = random.randint(0, 58)
rd2 = random.randint(0, 58)
pos_0 = barList[rd1]
pos_1 = barList[rd2]

swap_two_pos(pos_0, pos_1)
# it is necessary to swap the values in the list too
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]

window = tk.Tk()
window.title('Sorting')
window.geometry('600x400')

# button to command the swap
tk.Button(window, text='swap', command=random_swap).pack()
tk.Button(window, text='sort', command=sort).pack()

xstart = 5
xend = 15
canvas = tk.Canvas(window, width='900', height='900')
canvas.pack()
barList = []
lengthList = []
Y = 5

for x in range(1,60):
bar = canvas.create_rectangle(xstart, Y, xend, 395, fill='red')
barList.append(bar)
xstart += 10
xend += 10
Y += 5

for bar in barList:
x = canvas.coords(bar)
length = x[3]-x[1]
lengthList.append(length)

window.mainloop()

Visualising bubble sort using chart.js

You can use the setTimeout() method and update the labels, dataset.data and dataset.backgroundColor with a certain delay each time array elements are swapped. Then you also need to invoke chart.update() to make sure, Chart.js re-draws the updated chart on the canvas.

Please take a look at the runnable code below and see how it works.

function bubbleSort() {  
let labels = chart.data.labels;
let data = chart.data.datasets[0].data;
let colors = chart.data.datasets[0].backgroundColor;
let swapped;
let timeout = 0;
do {
swapped = false;
for (let i = 0; i < data.length; i++) {
if (data[i] > data[i + 1]) {
swap(labels, i);
swap(data, i);
swap(colors, i);
timeout += 50;
this.updateChartDelayed(labels.slice(0), data.slice(0), colors.slice(0), timeout);
swapped = true;
}
}
} while (swapped);
}

function swap(arr, i) {
let tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}

function updateChartDelayed(labels, data, colors, timeout) {
setTimeout(() => {
chart.data.labels = labels;
chart.data.datasets[0].data = data;
chart.data.datasets[0].backgroundColor = colors;
chart.update();
}, timeout);
}

const labels = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
const chart = new Chart('myChart', {
type: 'bar',
data: {
labels: labels,
datasets: [{
data: labels.map(() => Math.random()),
backgroundColor: ['#FF6633', '#FFB399', '#FF33FF', '#FFFF99', '#00B3E6', '#E6B333', '#3366E6', '#999966', '#99FF99', '#B34D4D', '#80B300', '#809900', '#E6B3B3', '#6680B3', '#66991A', '#66664D', '#991AFF', '#E666FF', '#4DB3FF', '#1AB399', '#4D8066', '#809980', '#E6FF80', '#1AFF33', '#999933', '#FF4D4D'],
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});

setTimeout(() => bubbleSort(), 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>


Related Topics



Leave a reply



Submit