In this code-along, we'll implement and analyze different sorting algorithms, focusing on their time complexity and practical applications.
Selection sort works by repeatedly finding the minimum element from the unsorted part of the array and putting it at the beginning.
public static void selectionSort(int[] arr) {
int n = arr.length;
// One by one move boundary of unsorted subarray
for (int i = 0; i < n - 1; i++) {
// Find the minimum element in unsorted array
int minIdx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
// Swap the found minimum element with the first element
int temp = arr[minIdx];
arr[minIdx] = arr[i];
arr[i] = temp;
}
}
Merge sort is a divide and conquer algorithm that divides the input array into two halves, recursively sorts them, and then merges the sorted halves.
public static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
// Find the middle point
int mid = left + (right - left) / 2;
// Sort first and second halves
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
// Merge the sorted halves
merge(arr, left, mid, right);
}
}
private static void merge(int[] arr, int left, int mid, int right) {
// Find sizes of two subarrays to be merged
int n1 = mid - left + 1;
int n2 = right - mid;
// Create temp arrays
int[] L = new int[n1];
int[] R = new int[n2];
// Copy data to temp arrays
for (int i = 0; i < n1; ++i) {
L[i] = arr[left + i];
}
for (int j = 0; j < n2; ++j) {
R[j] = arr[mid + 1 + j];
}
// Merge the temp arrays
int i = 0, j = 0;
int k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// Copy remaining elements of L[] if any
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
// Copy remaining elements of R[] if any
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
In this code-along, we'll implement recursive solutions to several problems and analyze their performance characteristics.
The factorial function is a classic example of recursion. It calculates the product of all positive integers less than or equal to n.
/**
* Calculate factorial recursively
* @param n The number to calculate factorial for
* @return n!
*/
public static long factorial(int n) {
// Base case
if (n == 0 || n == 1) {
return 1;
}
// Recursive case
return n * factorial(n - 1);
}
String reversal is another problem that can be solved elegantly with recursion.
/**
* Reverse a string using recursion
* @param str The string to reverse
* @return The reversed string
*/
public static String reverseString(String str) {
// Base case
if (str.isEmpty() || str.length() == 1) {
return str;
}
// Recursive case: first character goes to the end
return reverseString(str.substring(1)) + str.charAt(0);
}
During this code-along, we'll explore the tradeoffs between recursive and iterative solutions: