Sorting Algorithms in Java
In this notebook, we’ll implement various sorting algorithms in Java and test their performance. We’ll implement Bubble Sort, Selection Sort, Insertion Sort, Merge Sort, and Quick Sort. Additionally, we’ll create a generic TQueue
class with a Collectables
implementation to compare keys.
Bubble Sort
Bubble Sort is a simple sorting algorithm that repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the wrong order.
Time Complexity:
- Average Case: O(n^2)
- Worst Case: O(n^2)
// Bubble Sort Implementation
public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// swap arr[j] and arr[j+1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
Selection Sort
Selection Sort sorts an array by repeatedly finding the minimum element from the unsorted part and putting it at the beginning.
Time Complexity:
- Average Case: O(n^2)
- Worst Case: O(n^2)
// Selection Sort Implementation
public class SelectionSort {
public static void selectionSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// swap arr[i] and arr[minIndex]
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
}
Insertion Sort
Insertion Sort builds the final sorted array one item at a time by repeatedly picking the next item and inserting it into the sorted part.
Time Complexity:
- Average Case: O(n^2)
- Worst Case: O(n^2)
// Insertion Sort Implementation
public class InsertionSort {
public static void insertionSort(int[] arr) {
int n = arr.length;
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
}
Merge Sort
Merge Sort is a divide-and-conquer algorithm that divides the array into two halves, sorts each half separately, and then merges the sorted halves.
Time Complexity:
- Average Case: O(n log n)
- Worst Case: O(n log n)
// Merge Sort Implementation
public class MergeSort {
public static void mergeSort(int[] arr, int l, int r) {
if (l < r) {
int m = (l + r) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
private static void merge(int[] arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int[] L = new int[n1];
int[] R = new int[n2];
for (int i = 0; i < n1; ++i)
L[i] = arr[l + i];
for (int j = 0; j < n2; ++j)
R[j] = arr[m + 1 + j];
int i = 0, j = 0;
int k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
}
Quick Sort
Quick Sort is a highly efficient sorting algorithm based on the divide-and-conquer approach.
Time Complexity:
- Average Case: O(n log n)
- Worst Case: O(n^2)
// Quick Sort Implementation
public class QuickSort {
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pivotIndex = partition(arr, low, high);
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
}
Generic TQueue with Collectables Implementation
Let’s implement a generic TQueue
class with a Collectables
implementation to compare keys.
// TQueue with Collectables Implementation
import java.util.Comparator;
import java.util.PriorityQueue;
public class TQueue<T> {
private PriorityQueue<T> queue;
public TQueue() {
this.queue = new PriorityQueue<>();
}
public void enqueue(T element) {
queue.offer(element);
}
public T dequeue() {
return queue.poll();
}
public T peek() {
return queue.peek();
}
public boolean isEmpty() {
return queue.isEmpty();
}
public int size() {
return queue.size();
}
public static <T> void sortWithCollectables(T[] arr, Comparator<T> comparator) {
TQueue<T> tQueue = new TQueue<>();
for (T item : arr) {
tQueue.enqueue(item);
}
int index = 0;
while (!tQueue.isEmpty()) {
arr[index++] = tQueue.dequeue();
}
}
}
Tester Methods
Now, let’s implement tester methods to run each sorting algorithm.
// Tester Methods
import java.util.Arrays;
public class SortTester {
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
// Bubble Sort
System.out.println("Bubble Sort:");
BubbleSort.bubbleSort(arr.clone());
System.out.println(Arrays.toString(arr));
// Selection Sort
System.out.println("Selection Sort:");
SelectionSort.selectionSort(arr.clone());
System.out.println(Arrays.toString(arr));
// Insertion Sort
System.out.println("Insertion Sort:");
InsertionSort.insertionSort(arr.clone());
System.out.println(Arrays.toString(arr));
// Merge Sort
System.out.println("Merge Sort:");
MergeSort.mergeSort(arr.clone(), 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
// Quick Sort
System.out.println("Quick Sort:");
QuickSort.quickSort(arr.clone(), 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
}