0

I found this code here in the accepted answer: Java swing repainting while computing: animating sorting algorithm

And I've been trying to modify it so it works for shaker sort but my code sorts the whole thing all at once.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collections;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class ShakerSortAnimate extends JPanel {
private static final int NUM_OF_ITEMS = 20;
private static final int DIM_W = 400;
private static final int DIM_H = 400;
private static final int HORIZON = 350;
private static final int VERT_INC = 15;
private static final int HOR_INC = DIM_W / NUM_OF_ITEMS;

private JButton startButton;
private Timer timer = null;
private JButton resetButton;

Integer[] list;
int currentIndex = NUM_OF_ITEMS - 1;

public ShakerSortAnimate() {
    list = initList();

    timer = new Timer(200, new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if (isSortingDone()) {
                ((Timer) e.getSource()).stop();
                startButton.setEnabled(false);
            } else {
                sortOnlyOneItem();
            }
            repaint();
        }
    });

    //button to run the program
    startButton = new JButton("Start");
    startButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            timer.start();
        }
    });

    //resets screen
    resetButton = new JButton("Reset");
    resetButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            list = initList();
            currentIndex = NUM_OF_ITEMS - 1;
            repaint();
            startButton.setEnabled(true);
        }
    });
    add(startButton);
    add(resetButton);
}

//boolean checks when array is sorted
public boolean isSortingDone() {
    return currentIndex == 0;
}

//initializes the array
public Integer[] initList() { 
    Integer[] nums = new Integer[NUM_OF_ITEMS];
    for (int i = 1; i <= nums.length; i++) {
        nums[i - 1] = i;
    }
    Collections.shuffle(Arrays.asList(nums)); //shuffles array
    return nums;
}

//draws each bar
public void drawItem(Graphics g, int item, int index) {
    int height = item * VERT_INC;
    int y = HORIZON - height;
    int x = index * HOR_INC;
    g.fillRect(x, y, HOR_INC, height);
}


//My shaker sort code
public void sortOnlyOneItem()
{
    boolean swapped = true;
    int start = 0;
    int end = currentIndex;

    while (swapped==true)
    {
        swapped = false;

        for (int i = start; i < end; ++i)
        {
            if (list[i] > list[i + 1])
            {
                int temp = list[i];
                list[i] = list[i+1];
                list[i+1] = temp;
                swapped = true;
            }
        }

        if (swapped==false)
            break;

        swapped = false;

        end = end-1;

        for (int i = end; i >=start; i--)
        {
            if (list[i] > list[i+1])
            {
                int temp = list[i];
                list[i] = list[i+1];
                list[i+1] = temp;
                swapped = true;
            }
        }

        start = start + 1;
    }

   currentIndex--; //currentIndex is updated each time shaker sort runs
}






//draws all bars
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    for (int i = 0; i < list.length; i++) {
        drawItem(g, list[i], i);
    }
}

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

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame("Sort");
            frame.add(new ShakerSortAnimate());
            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}
  }

I do realize that my Shaker Sort code has to do it for each comparison, not the entire thing but honestly, I don't even know how to begin to code that. If anyone of you here knows how to code each comparison in shaker sort, can you help me out?

Btw, I posted the entire thing so you can try running this as well.

Thanks in advance!

  • 1
    You need to loops the `while (swapped)` statement, this needs to be taken care of by the `Timer`, which is a pseudo loop. It needs to determine if the another iteration needs to take place or not, and if so, call the `sortOnlyOneItem` method. This also means that `swapped`, `start` and `end` need to be instance fields – MadProgrammer Dec 04 '17 at 07:04

1 Answers1

1

So, you need this...

public void sortOnlyOneItem()
{
    boolean swapped = true;
    int start = 0;
    int end = currentIndex;

    while (swapped==true)
    {
        swapped = false;

        for (int i = start; i < end; ++i)
        {
            if (list[i] > list[i + 1])
            {
                int temp = list[i];
                list[i] = list[i+1];
                list[i+1] = temp;
                swapped = true;
            }
        }

        if (swapped==false)
            break;

        swapped = false;

        end = end-1;

        for (int i = end; i >=start; i--)
        {
            if (list[i] > list[i+1])
            {
                int temp = list[i];
                list[i] = list[i+1];
                list[i+1] = temp;
                swapped = true;
            }
        }

        start = start + 1;
    }

   currentIndex--; //currentIndex is updated each time shaker sort runs
}

To only run ONCE per call. It's not doing that right now because if the while-loop, so, we need to get rid of that.

In doing so, the second loop should only be run if swapped is true AND the currentIndex should only be decremented if swapped is still true

Which brings us to something like...

public void sortOnlyOneItem() {
    boolean swapped = true;
    int start = 0;
    int end = currentIndex;

    for (int i = start; i < end; ++i) {
        if (list[i] > list[i + 1]) {
            int temp = list[i];
            list[i] = list[i + 1];
            list[i + 1] = temp;
            swapped = true;
        }
    }

    if (swapped) {
        swapped = false;

        end = end - 1;

        for (int i = end; i >= start; i--) {
            if (list[i] > list[i + 1]) {
                int temp = list[i];
                list[i] = list[i + 1];
                list[i + 1] = temp;
                swapped = true;
            }
        }
    }

    if (swapped) {
        currentIndex--; //currentIndex is updated each time shaker sort runs
    }
}

Which still isn't quite right, as the two for-loops can make multiple changes.

Instead, we need a iteration which will only make, at most, two changes, one at the start and one at the end

Which, might, look something like...

protected void swap(int a, int b) {
    int tmp = list[a];
    list[a] = list[b];
    list[b] = tmp;
}

int endIndex = NUM_OF_ITEMS - 1;

//My shaker sort code
public void sortOnlyOneItem() {

    int startIndex = 0;
    while (startIndex < NUM_OF_ITEMS - 1 && list[startIndex] < list[startIndex + 1]) {
        startIndex++;
    }

    if (startIndex < NUM_OF_ITEMS - 1 && list[startIndex] > list[startIndex + 1]) {
        swap(startIndex, startIndex + 1);
        int end = endIndex;
        while (end > 0 && list[end - 1] < list[end]) {
            end--;
        }
        if (end > 0 && list[end - 1] > list[end]) {
            swap(end - 1, end);
        } else {
            endIndex--;
        }
    } else {
        endIndex = 0;
    }
}

Now, this basically looks for the two indices which might be changeable (at the start and end) and swaps them if possible. When you can iterate from the start to the end without making a change, the sort is finished.

Now, I make no claims over if this is accurate or not, only that it does the best effort to mimic the algorithm you supplied

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thank you so much for the answer! However, this code doesn't work the way a Shaker sort would, which I'm trying to figure out why... – TheDeadline Dec 04 '17 at 21:53
  • 1
    Which is partly what I expected, I've done my best to distill your algorithm down into a single step approach, but I've never implemented a "shaker" sort before, so I only had you code to go on. You will need to take the basic idea of what's been presented and devices the algorithm to meet your needs – MadProgrammer Dec 04 '17 at 22:14