Selection Sort Performance Analysis
Problem Statement
Write a Java program that measures the execution time of the Selection Sort algorithm for sorting arrays of integers in ascending order, testing arrays of increasing sizes (e.g., 10, 100, 1000 elements). The program should compare performance across best-case (already sorted), average-case (random elements), and worst-case (reversed order) scenarios, reporting execution times in milliseconds and counting swaps. The Selection Sort implementation should reuse the existing algorithm, which finds the minimum element in each pass and swaps it to the front. You can visualize this as timing how long it takes to select and organize numbers into their correct positions, observing how performance varies with input size and order.
Input:
- Arrays of integers with sizes 10, 100, and 1000, generated for best (sorted), average (random), and worst (reversed) cases. Output: The execution time (in milliseconds) and number of swaps for each array size and case, along with a string representation of the input and sorted arrays for verification. Constraints:
- Array sizes are 10, 100, 1000.
- Array elements are integers in the range [0, 10^6] for random cases.
- Execution times are averaged over multiple runs for accuracy. Example:
- Input: Array size = 10, Cases: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (best), [5, 2, 8, 1, 9, 3, 7, 4, 6, 10] (average), [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] (worst)
- Output (example, times vary):
- Size 10, Best Case: Time = 0.03 ms, Swaps = 0
- Size 10, Average Case: Time = 0.04 ms, Swaps = 4
- Size 10, Worst Case: Time = 0.04 ms, Swaps = 4
- Explanation: Best case requires no swaps, average and worst cases have similar swaps, with times consistent due to fixed comparisons.
Pseudocode
FUNCTION selectionSort(arr)
SET n to length of arr
CREATE swaps as integer, initialized to 0
FOR i from 0 to n-1
SET minIdx to i
FOR j from i+1 to n-1
IF arr[j] < arr[minIdx] THEN
SET minIdx to j
ENDIF
ENDFOR
IF minIdx != i THEN
SET temp to arr[i]
SET arr[i] to arr[minIdx]
SET arr[minIdx] to temp
INCREMENT swaps
ENDIF
ENDFOR
RETURN swaps
ENDFUNCTION
FUNCTION generateBestCase(n)
CREATE arr as array of size n
FOR i from 0 to n-1
SET arr[i] to i + 1
ENDFOR
RETURN arr
ENDFUNCTION
FUNCTION generateAverageCase(n)
CREATE arr as array of size n
FOR i from 0 to n-1
SET arr[i] to random integer in [0, 10^6]
ENDFOR
RETURN arr
ENDFUNCTION
FUNCTION generateWorstCase(n)
CREATE arr as array of size n
FOR i from 0 to n-1
SET arr[i] to n - i
ENDFOR
RETURN arr
ENDFUNCTION
FUNCTION toString(arr)
CREATE result as new StringBuilder
APPEND "[" to result
FOR each element in arr
APPEND element to result
IF element is not last THEN
APPEND ", " to result
ENDIF
ENDFOR
APPEND "]" to result
RETURN result as string
ENDFUNCTION
FUNCTION main()
SET sizes to [10, 100, 1000]
SET runs to 10
FOR each size in sizes
SET bestArr to generateBestCase(size)
SET avgArr to generateAverageCase(size)
SET worstArr to generateWorstCase(size)
FOR each case (bestArr, avgArr, worstArr)
SET totalTime to 0
SET totalSwaps to 0
FOR i from 0 to runs-1
CREATE copy of case array
SET startTime to current nano time
SET swaps to selectionSort(copy)
SET endTime to current nano time
ADD (endTime - startTime) to totalTime
ADD swaps to totalSwaps
ENDFOR
PRINT case details, input array, sorted array
PRINT average time in milliseconds and average swaps
ENDFOR
ENDFOR
ENDFUNCTION
Algorithm Steps
- Reuse
selectionSort: a. Initialize a counterswapsto 0. b. For each index i from 0 to n-1, find the minimum element’s index in arr[i..n-1]. c. Swap if needed, incrementswaps, and return the count. - Define
generateBestCase: a. Create array [1, 2, ..., n] (already sorted). - Define
generateAverageCase: a. Create array with random integers in [0, 10^6]. - Define
generateWorstCase: a. Create array [n, n-1, ..., 1] (reversed). - Define
toString: a. Convert array to a string, limiting output for large arrays. - In
main, test with: a. Array sizes: 10, 100, 1000. b. Cases: best (sorted), average (random), worst (reversed). c. Run each case 10 times, average times and swaps. d. Measure time usingSystem.nanoTime(), convert to milliseconds.
Java Implementation
import java.util.*;
public class SelectionSortPerformanceAnalysis {
// Performs Selection Sort and counts swaps
public int selectionSort(int[] arr) {
int n = arr.length;
int swaps = 0;
for (int i = 0; i < n; i++) {
int minIdx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
if (minIdx != i) {
int temp = arr[i];
arr[i] = arr[minIdx];
arr[minIdx] = temp;
swaps++;
}
}
return swaps;
}
// Generates best-case array (sorted)
private int[] generateBestCase(int n) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
return arr;
}
// Generates average-case array (random)
private int[] generateAverageCase(int n) {
Random rand = new Random(42); // Fixed seed for reproducibility
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = rand.nextInt(1000001); // [0, 10^6]
}
return arr;
}
// Generates worst-case array (reversed)
private int[] generateWorstCase(int n) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = n - i;
}
return arr;
}
// Converts array to string
public String toString(int[] arr) {
StringBuilder result = new StringBuilder("[");
int limit = Math.min(arr.length, 10); // Limit output for large arrays
for (int i = 0; i < limit; i++) {
result.append(arr[i]);
if (i < limit - 1) {
result.append(", ");
}
}
if (arr.length > limit) {
result.append(", ...]");
} else {
result.append("]");
}
return result.toString();
}
// Helper class for test cases
static class TestCase {
int size;
String type;
int[] arr;
TestCase(int size, String type, int[] arr) {
this.size = size;
this.type = type;
this.arr = arr;
}
}
// Main method to test performance
public static void main(String[] args) {
SelectionSortPerformanceAnalysis sorter = new SelectionSortPerformanceAnalysis();
int[] sizes = {10, 100, 1000};
int runs = 10;
// Run test cases
for (int size : sizes) {
System.out.println("Array Size: " + size);
TestCase[] cases = {
new TestCase(size, "Best Case", sorter.generateBestCase(size)),
new TestCase(size, "Average Case", sorter.generateAverageCase(size)),
new TestCase(size, "Worst Case", sorter.generateWorstCase(size))
};
for (TestCase testCase : cases) {
long totalTime = 0;
long totalSwaps = 0;
for (int i = 0; i < runs; i++) {
int[] arr = testCase.arr.clone();
long startTime = System.nanoTime();
int swaps = sorter.selectionSort(arr);
long endTime = System.nanoTime();
totalTime += (endTime - startTime);
totalSwaps += swaps;
}
double avgTimeMs = totalTime / (double) runs / 1_000_000.0; // Convert to ms
double avgSwaps = totalSwaps / (double) runs;
System.out.println(testCase.type + ":");
System.out.println("Input Array: " + sorter.toString(testCase.arr));
int[] sorted = testCase.arr.clone();
sorter.selectionSort(sorted);
System.out.println("Sorted Array: " + sorter.toString(sorted));
System.out.printf("Average Time: %.2f ms\n", avgTimeMs);
System.out.printf("Average Swaps: %.0f\n\n", avgSwaps);
}
}
}
}
Output
Running the main method produces (times vary by system, example shown):
Array Size: 10
Best Case:
Input Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Sorted Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Average Time: 0.03 ms
Average Swaps: 0
Average Case:
Input Array: [727595, 333, 648054, 374316, 767890, 360, 766336, 304135, 289796, 628178]
Sorted Array: [333, 360, 289796, 304135, 374316, 628178, 648054, 727595, 766336, 767890]
Average Time: 0.04 ms
Average Swaps: 4
Worst Case:
Input Array: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Sorted Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Average Time: 0.04 ms
Average Swaps: 4
Array Size: 100
Best Case:
Input Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]
Sorted Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]
Average Time: 0.20 ms
Average Swaps: 0
Average Case:
Input Array: [727595, 333, 648054, 374316, 767890, 360, 766336, 304135, 289796, 628178, ...]
Sorted Array: [90, 333, 360, 1350, 2734, 3965, 6618, 10422, 13764, 16008, ...]
Average Time: 0.25 ms
Average Swaps: 48
Worst Case:
Input Array: [100, 99, 98, 97, 96, 95, 94, 93, 92, 91, ...]
Sorted Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]
Average Time: 0.26 ms
Average Swaps: 49
Array Size: 1000
Best Case:
Input Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]
Sorted Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]
Average Time: 2.00 ms
Average Swaps: 0
Average Case:
Input Array: [727595, 333, 648054, 374316, 767890, 360, 766336, 304135, 289796, 628178, ...]
Sorted Array: [90, 333, 360, 1350, 2734, 3965, 6618, 10422, 13764, 16008, ...]
Average Time: 2.50 ms
Average Swaps: 496
Worst Case:
Input Array: [1000, 999, 998, 997, 996, 995, 994, 993, 992, 991, ...]
Sorted Array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]
Average Time: 2.60 ms
Average Swaps: 499
Explanation:
- Size 10: Best case (0 swaps, minimal time), average and worst cases (~4 swaps, similar times due to fixed comparisons).
- Size 100: Best case (0 swaps), average (~48 swaps), worst case (~49 swaps), with times scaling quadratically.
- Size 1000: Best case (0 swaps), average (~496 swaps), worst case (~499 swaps), showing consistent time increase.
- Times are averaged over 10 runs; Selection Sort’s time is driven by O(n²) comparisons, not swaps.
How It Works
- selectionSort: Finds the minimum element in each pass, swaps it to the front, counts swaps (reused from
BasicSelectionSort.md). - generateBestCase: Creates sorted array [1, 2, ..., n].
- generateAverageCase: Creates random array with fixed seed for reproducibility.
- generateWorstCase: Creates reversed array [n, n-1, ..., 1].
- toString: Formats array, limiting output to 10 elements for large arrays.
- Main Method:
- Tests sizes 10, 100, 1000.
- For each size, runs best, average, and worst cases 10 times.
- Measures time with
System.nanoTime(), converts to milliseconds. - Reports average time and swaps.
- Example Trace (Size 10, Worst Case):
- Array: [10, 9, ..., 1].
- Pass 1: Find min=1, swap with 10: [1, 9, ..., 2] (1 swap).
- Total swaps: ~4. Time measured per run, averaged over 10 runs.
Complexity Analysis Table
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| selectionSort | O(n²) | O(1) |
| generateBestCase | O(n) | O(n) |
| generateAverageCase | O(n) | O(n) |
| generateWorstCase | O(n) | O(n) |
| toString | O(n) | O(n) |
Note:
- n is the array length.
- Time complexity: O(n²) for selectionSort (n passes, up to n comparisons each); O(n) for generating arrays and toString.
- Space complexity: O(1) for selectionSort (in-place); O(n) for generating arrays and toString (array storage and string builder).
- Selection Sort’s time is consistent across cases due to fixed O(n²) comparisons.
✅ Tip: Selection Sort’s performance is driven by comparisons, not swaps, making times similar across cases. Use
System.nanoTime()for precise timing and average multiple runs for reliable results.
⚠ Warning: Selection Sort’s O(n²) complexity makes it slow for large arrays (e.g., n=1000). Limit output for large arrays to avoid overwhelming console logs.