diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 7e0010e..4379e7f 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -9,5 +9,8 @@ + + + \ No newline at end of file diff --git a/src/main/java/algorithms/BubbleSort.java b/src/main/java/algorithms/BubbleSort.java index 02361d9..78eff60 100644 --- a/src/main/java/algorithms/BubbleSort.java +++ b/src/main/java/algorithms/BubbleSort.java @@ -3,25 +3,41 @@ import ui.Utils; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; public class BubbleSort extends AlgorithmSort { public BubbleSort(ArrayList array) { - super(array); + super(array); } + @Override public void sort() { + int SLEEP_DURATION = 5; + + if (array.isEmpty()) { + System.out.println("Array is empty, nothing to sort."); + return; + } + int n = array.size(); + Set sortedIndices = new HashSet<>(); for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { + // Visualize the comparison + Utils.displayVerticalArray(array, j, j + 1, sortedIndices); + if (array.get(j) > array.get(j + 1)) { - int temp = array.get(j); - array.set(j, array.get(j + 1)); - array.set(j + 1, temp); - Utils.printArray(array); + // Swap and visualize the result of the selection for this iteration + Utils.swapHighlighted(array, j, j + 1, sortedIndices, SLEEP_DURATION); } } + // Mark the current position as sorted + sortedIndices.add(n - i - 1); } - } + // Final visualization with all elements highlighted in green + Utils.displayVerticalArray(array, -1, -1, sortedIndices); + } } diff --git a/src/main/java/algorithms/InsertionSort.java b/src/main/java/algorithms/InsertionSort.java index 444a0a8..ceb72d8 100644 --- a/src/main/java/algorithms/InsertionSort.java +++ b/src/main/java/algorithms/InsertionSort.java @@ -3,6 +3,8 @@ import ui.Utils; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; public class InsertionSort extends AlgorithmSort { @@ -12,23 +14,84 @@ public InsertionSort(ArrayList array) { @Override public void sort() { + int SLEEP_DURATION = 10; + Set sortedIndices = new HashSet<>(); if (array.isEmpty()) { System.out.println("Array is empty, nothing to sort."); return; } + int n = array.size(); for (int i = 1; i < n; i++) { int key = array.get(i); int j = i - 1; + // Highlight the initial key element before shifting + highlightInsertion(array, i, -1, -1, sortedIndices, SLEEP_DURATION); + + // Shift elements to the right and highlight each shift while (j >= 0 && array.get(j) > key) { array.set(j + 1, array.get(j)); + highlightInsertion(array, i, j, j + 1, sortedIndices, SLEEP_DURATION); j = j - 1; } + + // Place the key in the correct position array.set(j + 1, key); + highlightInsertion(array, -1, j + 1, j + 1, sortedIndices, SLEEP_DURATION); + + // Mark the element as sorted + sortedIndices.add(i); + } + + // Mark all elements as sorted for the final display + Utils.displayVerticalArray(array, -1, -1, sortedIndices); + } + + static void highlightInsertion(ArrayList arrayList, int keyIndex, int shiftIndex, int targetIndex, Set sortedIndices, int sleepDuration) { + final String RESET = "\033[0m"; + final String YELLOW = "\033[33m"; // Key element + final String RED = "\033[31m"; // Shifted elements + final String BLUE = "\033[34m"; // Target position + final String GREEN = "\033[32m"; // Sorted elements - Utils.printArray(array); + StringBuilder output = new StringBuilder(); + int maxHeight = Utils.findMax(arrayList); + + for (int row = maxHeight; row > 0; row--) { + output.append("\033[2K"); // Clear the whole line + + for (int col = 0; col < arrayList.size(); col++) { + int element = arrayList.get(col); + + if (element >= row) { + if (sortedIndices.contains(col)) { + output.append(GREEN).append("#").append(RESET); + } else if (col == keyIndex) { + output.append(YELLOW).append("#").append(RESET); + } else if (col == shiftIndex) { + output.append(RED).append("#").append(RESET); + } else if (col == targetIndex) { + output.append(BLUE).append("#").append(RESET); + } else { + output.append("#"); + } + } else { + output.append(" "); + } + } + output.append("\n"); + } + + System.out.print(output.toString()); + System.out.print("\033[" + maxHeight + "F"); + + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); } } + } diff --git a/src/main/java/algorithms/QuickSort.java b/src/main/java/algorithms/QuickSort.java index cd9cb75..3626524 100644 --- a/src/main/java/algorithms/QuickSort.java +++ b/src/main/java/algorithms/QuickSort.java @@ -3,6 +3,8 @@ import ui.Utils; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; public class QuickSort extends AlgorithmSort { @@ -12,23 +14,27 @@ public QuickSort(ArrayList array) { @Override public void sort() { - quickSort(0, array.size() - 1); + int SLEEP_DURATION = 30; + + Set sortedIndices = new HashSet<>(); + quickSort(0, array.size() - 1, sortedIndices, SLEEP_DURATION); + Utils.displayVerticalArray(array, -1, -1, sortedIndices); } - void quickSort(int start, int end) { + void quickSort(int start, int end, Set sortedIndices, int sleepDuration) { if (start < end) { // pi is the partition return index of pivot - int pi = partition(start, end); + int pi = partition(start, end, sortedIndices, sleepDuration); // Recursion calls for smaller elements // and greater or equals elements - quickSort(start, pi - 1); - quickSort(pi + 1, end); + quickSort(start, pi - 1, sortedIndices, sleepDuration); + quickSort(pi + 1, end, sortedIndices, sleepDuration); } } // Partition function - int partition(int start, int end) { + int partition(int start, int end, Set sortedIndices, int sleepDuration) { int pivot = array.get(end); // Index of smaller element and indicates @@ -36,8 +42,9 @@ int partition(int start, int end) { int pIndex = start; for (int i = start; i <= end - 1; i++) { + Utils.displayVerticalArray(array, i, end, sortedIndices); if (array.get(i) <= pivot) { - Utils.swap(array, pIndex, end); + Utils.swapHighlighted(array, pIndex, i, sortedIndices, sleepDuration); pIndex++; } } @@ -48,9 +55,9 @@ int partition(int start, int end) { // Move pivot after smaller elements and // return its position - Utils.swap(array, pIndex, end); + Utils.swapHighlighted(array, pIndex, end, sortedIndices, sleepDuration); // Move pivot to correct position + sortedIndices.add(pIndex); return pIndex; } - } diff --git a/src/main/java/algorithms/SelectionSort.java b/src/main/java/algorithms/SelectionSort.java index 4469f7f..b188369 100644 --- a/src/main/java/algorithms/SelectionSort.java +++ b/src/main/java/algorithms/SelectionSort.java @@ -3,6 +3,8 @@ import ui.Utils; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; public class SelectionSort extends AlgorithmSort { @@ -12,6 +14,7 @@ public SelectionSort(ArrayList array) { @Override public void sort() { + int SLEEP_DURATION = 25; if (array.isEmpty()) { System.out.println("Array is empty, nothing to sort."); @@ -19,22 +22,36 @@ public void sort() { } int n = array.size(); + Set sortedIndices = new HashSet<>(); + for (int i = 0; i < n - 1; i++) { int currentMin = i; for (int j = i + 1; j < n; j++) { + // Visualize the comparison + Utils.displayVerticalArray(array, i, j, sortedIndices); + if (array.get(j) < array.get(currentMin)) { currentMin = j; } } + // Swap and visualize the result of the selection for this iteration if (currentMin != i) { - int temp = array.get(i); - array.set(i, array.get(currentMin)); - array.set(currentMin, temp); + Utils.swapHighlighted(array, i, currentMin, sortedIndices, SLEEP_DURATION); } - Utils.printArray(array); + // Mark the current position as sorted + sortedIndices.add(i); + } + + // Ensure all elements are marked as sorted for the final display + for (int i = 0; i < n; i++) { + sortedIndices.add(i); } + + // Final visualization with all elements highlighted in green + Utils.displayVerticalArray(array, -1, -1, sortedIndices); } } + diff --git a/src/main/java/ui/TestUI.java b/src/main/java/ui/TestUI.java index f2394a3..be6c3b8 100644 --- a/src/main/java/ui/TestUI.java +++ b/src/main/java/ui/TestUI.java @@ -1,6 +1,9 @@ package ui; import algorithms.BubbleSort; +import algorithms.InsertionSort; +import algorithms.QuickSort; +import algorithms.SelectionSort; import java.util.ArrayList; import java.util.List; @@ -10,17 +13,24 @@ public static void start() { ArrayList list = new ArrayList<>(List.of( 10, 17, 9, 19, 15, 7, 6, 4, 7, 6, - 6, 20, 17, 6, 5, 8, 8, 5, 17, 18, - 16, 17, 10, 1, 18, 4, 6, 20, 9, 14, - 7, 4, 15, 7, 6, 2, 15, 15, 3, 1, 9, - 2, 19, 8, 16, 14, 19, 5, 20, 9 + 6, 20, 17, 6, 5, 8, 8, 5, 17, 18, + 16, 17, 10, 1, 18, 4, 6, 20, 9, 14, + 7, 4, 15, 7, 6, 2, 15, 15, 3, 1, 9, + 2, 19, 8, 16, 14, 19, 5, 20, 9 )); BubbleSort bubbleSort = new BubbleSort(list); + //bubbleSort.sort(); - bubbleSort.sort(); + SelectionSort selectionSort = new SelectionSort(list); + //selectionSort.sort(); - Utils.printArray(list); - } + QuickSort quickSort = new QuickSort(list); + //quickSort.sort(); + + InsertionSort insertionSort = new InsertionSort(list); + insertionSort.sort(); + + } } diff --git a/src/main/java/ui/Utils.java b/src/main/java/ui/Utils.java index 8f7909e..eba8d96 100644 --- a/src/main/java/ui/Utils.java +++ b/src/main/java/ui/Utils.java @@ -3,6 +3,7 @@ import io.github.shuoros.jterminal.JTerminal; import java.util.ArrayList; +import java.util.Set; public abstract class Utils { // change to ### view @@ -26,7 +27,7 @@ public static void printArray(ArrayList arrayList) { } - private static int findMax(ArrayList array) { + public static int findMax(ArrayList array) { int max = 0; for (var element : array) { if (element > max) max = element; @@ -42,5 +43,71 @@ public static void swap(ArrayList arr, int i, int j) { Utils.printArray(arr); } + public static void swapHighlighted(ArrayList arr, int currentIndex, int targetIndex, Set sortedIndices, int sleepDuration) { + + displayVerticalArray(arr, currentIndex, targetIndex, sortedIndices); + try { + Thread.sleep(sleepDuration); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + // Perform the swap + int temp = arr.get(currentIndex); + arr.set(currentIndex, arr.get(targetIndex)); + arr.set(targetIndex, temp); + + displayVerticalArray(arr, currentIndex, targetIndex, sortedIndices); + try { + Thread.sleep(sleepDuration); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + + public static void displayVerticalArray(ArrayList arrayList, int currentIndex, int targetIndex, Set sortedIndices) { + final String RESET = "\033[0m"; + final String RED = "\033[31m"; // comparison element + final String BLUE = "\033[34m"; // target element + final String GREEN = "\033[32m"; // sorted elements + StringBuilder output = new StringBuilder(); + + int maxHeight = findMax(arrayList); + + for (int row = maxHeight; row > 0; row--) { + // is used to clear the current line before printing new content for improving animation smoothness + output.append("\033[2K"); // Clear the whole line + for (int col = 0; col < arrayList.size(); col++) { + int element = arrayList.get(col); + if (element >= row) { + if (sortedIndices.contains(col)) { + output.append(GREEN).append("#").append(RESET); + } else if (col == currentIndex) { + output.append(RED).append("#").append(RESET); + } else if (col == targetIndex) { + output.append(BLUE).append("#").append(RESET); + } else { + output.append("#"); + } + } else { + output.append(" "); + } + } + output.append("\n"); + } + + System.out.print(output.toString()); + + /* + Repositioning the cursor: + - makes the visualization smoother; + - reduces flicker; + - improves performance by avoiding full-screen clearing. + */ + System.out.print("\033[" + maxHeight + "F"); // Move cursor up to the top + } + + // fillArrayRandomlyMethod (between 1 and 100 for example) } \ No newline at end of file diff --git a/target/classes/META-INF/MANIFEST.MF b/target/classes/META-INF/MANIFEST.MF new file mode 100644 index 0000000..37197ef --- /dev/null +++ b/target/classes/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Main + diff --git a/target/classes/main/resources/META-INF/MANIFEST.MF b/target/classes/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..37197ef --- /dev/null +++ b/target/classes/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Main + diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..3d04e33 --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,4 @@ +#Created by Apache Maven 3.9.9 +artifactId=sar +groupId=sorting.algorithm.visualization +version=1.0-SNAPSHOT diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..92f57d8 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,5 @@ +ui/Utils.class +Main.class +ui/TestUI.class +algorithms/AlgorithmSort.class +algorithms/BubbleSort.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..97b8af2 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,5 @@ +/Users/nat-lee/Documents/WORK-CODE/DCI/PROJECTS/sorting-algorithm-visualisation/src/main/java/algorithms/BubbleSort.java +/Users/nat-lee/Documents/WORK-CODE/DCI/PROJECTS/sorting-algorithm-visualisation/src/main/java/Main.java +/Users/nat-lee/Documents/WORK-CODE/DCI/PROJECTS/sorting-algorithm-visualisation/src/main/java/ui/TestUI.java +/Users/nat-lee/Documents/WORK-CODE/DCI/PROJECTS/sorting-algorithm-visualisation/src/main/java/algorithms/AlgorithmSort.java +/Users/nat-lee/Documents/WORK-CODE/DCI/PROJECTS/sorting-algorithm-visualisation/src/main/java/ui/Utils.java