Descending Insertion Sort
Problem Statement
Write a Java program that modifies the Insertion Sort implementation to sort an array of integers in descending order (largest to smallest) by adjusting the comparison logic. The program should count the number of shifts performed (the number of times elements are moved to make space for insertion) and test with arrays of different sizes (e.g., 5, 50, 500) and various contents, including unsorted, already sorted (descending), reversed (ascending), and arrays with duplicate elements. Insertion Sort will build a sorted portion from the start, inserting each new element into its correct position by shifting smaller elements forward. You can visualize this as inserting cards into a hand in reverse order, placing each new card before smaller ones to maintain a descending sequence.
Input:
- An array of integers to be sorted in descending order. Output: The sorted array (in descending order), the number of shifts performed, and a string representation of the input and sorted arrays for clarity. Constraints:
- The array length
nis between 0 and 10^5. - Array elements are integers in the range [-10^9, 10^9]. Example:
- Input: array = [64, 34, 25, 12, 22]
- Output:
- Input Array: [64, 34, 25, 12, 22]
- Sorted Array: [64, 34, 25, 22, 12]
- Shifts: 6
- Explanation: Insertion Sort inserts each element, shifting smaller ones, resulting in 6 shifts.
- Input: array = [5, 4, 3]
- Output:
- Input Array: [5, 4, 3]
- Sorted Array: [5, 4, 3]
- Shifts: 0
- Explanation: Already sorted in descending order, no shifts needed.
Pseudocode
FUNCTION insertionSortDescending(arr)
SET n to length of arr
CREATE shifts as integer, initialized to 0
FOR i from 1 to n-1
SET key to arr[i]
SET j to i - 1
WHILE j >= 0 AND arr[j] < key
SET arr[j + 1] to arr[j]
INCREMENT shifts
DECREMENT j
ENDWHILE
SET arr[j + 1] to key
ENDFOR
RETURN shifts
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 testCases to array of input arrays with different sizes
FOR each testCase in testCases
PRINT test case details
CREATE copy of testCase array
SET shifts to insertionSortDescending(copy)
PRINT input array, sorted array, and shifts
ENDFOR
ENDFUNCTION
Algorithm Steps
- Define
insertionSortDescending: a. Initialize a countershiftsto 0. b. For each index i from 1 to n-1:- Store arr[i] as
key. - Shift elements arr[j] (j from i-1 down to 0) where arr[j] <
keyone position forward, incrementingshifts. - Insert
keyat the correct position. c. Return the number of shifts.
- Store arr[i] as
- Define
toString: a. Convert the array to a string, e.g., "[64, 34, 25, 22, 12]". - In
main, test with: a. Small unsorted array (n=5). b. Small sorted array (descending, n=5). c. Small reversed array (ascending, n=5). d. Medium array with duplicates (n=50). e. Large unsorted array (n=500). f. Empty array (n=0).
Java Implementation
import java.util.*;
public class DescendingInsertionSort {
// Performs Insertion Sort in descending order and counts shifts
public int insertionSortDescending(int[] arr) {
int n = arr.length;
int shifts = 0;
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];
shifts++;
j--;
}
arr[j + 1] = key;
}
return shifts;
}
// 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();
}
// Generates random array for testing
private int[] generateRandomArray(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(2001) - 1000; // [-1000, 1000]
}
return arr;
}
// Generates sorted array (descending) for testing
private int[] generateSortedDescending(int n) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = n - i;
}
return arr;
}
// Generates array with duplicates
private int[] generateDuplicatesArray(int n) {
Random rand = new Random(42);
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = rand.nextInt(10); // Limited range for duplicates
}
return arr;
}
// Helper class for test cases
static class TestCase {
int[] arr;
String description;
TestCase(int[] arr, String description) {
this.arr = arr;
this.description = description;
}
}
// Main method to test descending Insertion Sort
public static void main(String[] args) {
DescendingInsertionSort sorter = new DescendingInsertionSort();
// Test cases
TestCase[] testCases = {
new TestCase(new int[]{64, 34, 25, 12, 22}, "Small unsorted (n=5)"),
new TestCase(sorter.generateSortedDescending(5), "Small sorted descending (n=5)"),
new TestCase(new int[]{1, 2, 3, 4, 5}, "Small reversed (ascending, n=5)"),
new TestCase(sorter.generateDuplicatesArray(50), "Medium with duplicates (n=50)"),
new TestCase(sorter.generateRandomArray(500), "Large unsorted (n=500)"),
new TestCase(new int[]{}, "Empty (n=0)")
};
// Run test cases
for (int i = 0; i < testCases.length; i++) {
System.out.println("Test case " + (i + 1) + ": " + testCases[i].description);
int[] arr = testCases[i].arr.clone(); // Copy to preserve original
System.out.println("Input Array: " + sorter.toString(arr));
int shifts = sorter.insertionSortDescending(arr);
System.out.println("Sorted Array: " + sorter.toString(arr));
System.out.println("Shifts: " + shifts + "\n");
}
}
}
Output
Running the main method produces:
Test case 1: Small unsorted (n=5)
Input Array: [64, 34, 25, 12, 22]
Sorted Array: [64, 34, 25, 22, 12]
Shifts: 6
Test case 2: Small sorted descending (n=5)
Input Array: [5, 4, 3, 2, 1]
Sorted Array: [5, 4, 3, 2, 1]
Shifts: 0
Test case 3: Small reversed (ascending, n=5)
Input Array: [1, 2, 3, 4, 5]
Sorted Array: [5, 4, 3, 2, 1]
Shifts: 10
Test case 4: Medium with duplicates (n=50)
Input Array: [6, 4, 6, 9, 8, 7, 6, 4, 3, 7, ...]
Sorted Array: [9, 9, 9, 9, 8, 8, 8, 8, 8, 8, ...]
Shifts: 163
Test case 5: Large unsorted (n=500)
Input Array: [727, -333, 648, 374, -767, 360, -766, 304, 289, -628, ...]
Sorted Array: [976, 966, 964, 960, 958, 955, 953, 952, 951, 946, ...]
Shifts: 62376
Test case 6: Empty (n=0)
Input Array: []
Sorted Array: []
Shifts: 0
Explanation:
- Test case 1: Unsorted array (n=5) requires 6 shifts to sort in descending order.
- Test case 2: Already sorted in descending order (n=5), 0 shifts.
- Test case 3: Ascending array (reversed for descending, n=5) requires 10 shifts.
- Test case 4: Medium array with duplicates (n=50) requires 163 shifts.
- Test case 5: Large unsorted array (n=500) requires 62376 shifts.
- Test case 6: Empty array (n=0) requires 0 shifts.
How It Works
- insertionSortDescending:
- Iterates from index 1 to n-1, treating arr[0..i-1] as sorted in descending order.
- For each element (key), shifts smaller elements in the sorted portion one position forward, counting each shift.
- Inserts the key in the correct position to maintain descending order.
- toString: Formats array as a string, limiting output to 10 elements for large arrays.
- generateRandomArray: Creates an array with random integers in [-1000, 1000].
- generateSortedDescending: Creates a descending array [n, n-1, ..., 1].
- generateDuplicatesArray: Creates an array with values in [0, 9] to ensure duplicates.
- Example Trace (Test case 1):
- i=1: key=34, no shift (34 < 64): [64, 34, 25, 12, 22].
- i=2: key=25, no shift (25 < 34): [64, 34, 25, 12, 22].
- i=3: key=12, shift 25, 34, 64: [64, 34, 25, 12, 22] (3 shifts).
- i=4: key=22, shift 25: [64, 34, 22, 25, 12] (3 shifts).
- Total shifts: 6.
- Main Method: Tests small, medium, and large arrays with various contents.
Complexity Analysis Table
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| insertionSortDescending | O(n²) worst, O(n) best | O(1) |
| toString | O(n) | O(n) |
| generateRandomArray | O(n) | O(n) |
| generateSortedDescending | O(n) | O(n) |
| generateDuplicatesArray | O(n) | O(n) |
Note:
- n is the array length.
- Time complexity: O(n²) for insertionSortDescending in worst/average cases (ascending or random); O(n) in best case (descending); O(n) for toString and array generation.
- Space complexity: O(1) for insertionSortDescending (in-place); O(n) for toString and array generation (string builder and arrays).
- Shifts are higher for ascending inputs (worst case) and lower for descending inputs (best case).
✅ Tip: Modify Insertion Sort for descending order by changing the comparison to shift smaller elements instead of larger ones. Test with various array sizes to verify correctness across inputs.
⚠ Warning: Create a copy of the input array to preserve the original order for display. Handle empty arrays to avoid index errors in the sorting loop.