Skip to content

Commit 86ebecc

Browse files
authored
Merge pull request #175 from Pasan11504/feature/add-counting-sort-java
Add Counting Sort implementation in Java
2 parents 987dbb7 + 8186312 commit 86ebecc

1 file changed

Lines changed: 280 additions & 0 deletions

File tree

Java/sorting/CountingSort.java

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
/**
2+
* Problem: Counting Sort Algorithm
3+
*
4+
* Description:
5+
* Counting Sort is a non-comparison based sorting algorithm that sorts elements
6+
* by counting the number of occurrences of each unique element in the array.
7+
* It works by determining, for each input element, the number of elements that
8+
* are less than it. This information is used to place the element directly into
9+
* its correct position in the sorted array.
10+
*
11+
* Algorithm:
12+
* 1. Find the range of input data (max and min values)
13+
* 2. Create a count array to store frequency of each element
14+
* 3. Modify count array by adding previous counts (cumulative count)
15+
* 4. Build output array by placing elements at their correct positions
16+
* 5. Copy output array back to original array
17+
*
18+
* Time Complexity: O(n + k) where n = number of elements, k = range of input
19+
* Space Complexity: O(n + k)
20+
*
21+
* Best for:
22+
* - Small range of integers
23+
* - When range of input is not significantly greater than number of elements
24+
* - Stable sorting is required
25+
*
26+
* Advantages:
27+
* - Linear time complexity for small range of integers
28+
* - Stable sorting algorithm (maintains relative order)
29+
* - Simple to understand and implement
30+
*
31+
* Disadvantages:
32+
* - Not suitable for large range of values
33+
* - Only works with non-negative integers (can be modified for negatives)
34+
* - Requires extra space proportional to the range of data
35+
*
36+
* @author DSA-Collection Contributors
37+
* @date October 2025
38+
*/
39+
40+
import java.util.Arrays;
41+
42+
public class CountingSort {
43+
44+
/**
45+
* Sorts an array of non-negative integers using Counting Sort algorithm.
46+
*
47+
* @param arr The array to be sorted (must contain non-negative integers)
48+
* @throws IllegalArgumentException if array contains negative numbers
49+
*/
50+
public static void countingSort(int[] arr) {
51+
// Handle edge cases
52+
if (arr == null || arr.length <= 1) {
53+
return;
54+
}
55+
56+
// Step 1: Find the range of input data (max and min)
57+
int max = arr[0];
58+
int min = arr[0];
59+
60+
for (int i = 1; i < arr.length; i++) {
61+
if (arr[i] > max) {
62+
max = arr[i];
63+
}
64+
if (arr[i] < min) {
65+
min = arr[i];
66+
}
67+
}
68+
69+
// Check for negative numbers
70+
if (min < 0) {
71+
throw new IllegalArgumentException(
72+
"Counting Sort requires non-negative integers. Found: " + min
73+
);
74+
}
75+
76+
// Step 2: Create count array to store frequency of each element
77+
// Size is (max + 1) to accommodate all values from 0 to max
78+
int range = max + 1;
79+
int[] count = new int[range];
80+
81+
// Count occurrences of each element
82+
for (int i = 0; i < arr.length; i++) {
83+
count[arr[i]]++;
84+
}
85+
86+
// Step 3: Modify count array by doing cumulative count
87+
// count[i] now contains actual position of this element in output array
88+
for (int i = 1; i < range; i++) {
89+
count[i] += count[i - 1];
90+
}
91+
92+
// Step 4: Build the output array
93+
// We build from right to left to maintain stability
94+
int[] output = new int[arr.length];
95+
for (int i = arr.length - 1; i >= 0; i--) {
96+
int element = arr[i];
97+
int position = count[element] - 1;
98+
output[position] = element;
99+
count[element]--; // Decrease count for next occurrence
100+
}
101+
102+
// Step 5: Copy the sorted elements back to original array
103+
System.arraycopy(output, 0, arr, 0, arr.length);
104+
}
105+
106+
/**
107+
* Alternative implementation that handles negative numbers as well.
108+
* Uses offset to handle negative values.
109+
*
110+
* @param arr The array to be sorted (can contain negative integers)
111+
*/
112+
public static void countingSortWithNegatives(int[] arr) {
113+
if (arr == null || arr.length <= 1) {
114+
return;
115+
}
116+
117+
// Find max and min to determine range and offset
118+
int max = arr[0];
119+
int min = arr[0];
120+
121+
for (int i = 1; i < arr.length; i++) {
122+
if (arr[i] > max) {
123+
max = arr[i];
124+
}
125+
if (arr[i] < min) {
126+
min = arr[i];
127+
}
128+
}
129+
130+
int range = max - min + 1;
131+
int offset = -min; // Offset to handle negative numbers
132+
133+
// Create count array
134+
int[] count = new int[range];
135+
136+
// Count occurrences (with offset for negative numbers)
137+
for (int i = 0; i < arr.length; i++) {
138+
count[arr[i] + offset]++;
139+
}
140+
141+
// Modify count array (cumulative)
142+
for (int i = 1; i < range; i++) {
143+
count[i] += count[i - 1];
144+
}
145+
146+
// Build output array (maintain stability)
147+
int[] output = new int[arr.length];
148+
for (int i = arr.length - 1; i >= 0; i--) {
149+
int element = arr[i];
150+
int position = count[element + offset] - 1;
151+
output[position] = element;
152+
count[element + offset]--;
153+
}
154+
155+
// Copy back to original array
156+
System.arraycopy(output, 0, arr, 0, arr.length);
157+
}
158+
159+
/**
160+
* Utility method to print array
161+
*/
162+
private static void printArray(String label, int[] arr) {
163+
System.out.print(label + ": ");
164+
System.out.println(Arrays.toString(arr));
165+
}
166+
167+
/**
168+
* Verify if array is sorted
169+
*/
170+
private static boolean isSorted(int[] arr) {
171+
for (int i = 0; i < arr.length - 1; i++) {
172+
if (arr[i] > arr[i + 1]) {
173+
return false;
174+
}
175+
}
176+
return true;
177+
}
178+
179+
/**
180+
* Main method with comprehensive test cases
181+
*/
182+
public static void main(String[] args) {
183+
System.out.println("=== Counting Sort Algorithm Implementation ===\n");
184+
185+
// Test Case 1: Standard array
186+
System.out.println("Test Case 1: Standard Array");
187+
int[] test1 = {4, 2, 2, 8, 3, 3, 1};
188+
printArray("Original", test1);
189+
countingSort(test1);
190+
printArray("Sorted ", test1);
191+
System.out.println("Is sorted: " + isSorted(test1));
192+
System.out.println();
193+
194+
// Test Case 2: Already sorted array
195+
System.out.println("Test Case 2: Already Sorted Array");
196+
int[] test2 = {1, 2, 3, 4, 5};
197+
printArray("Original", test2);
198+
countingSort(test2);
199+
printArray("Sorted ", test2);
200+
System.out.println("Is sorted: " + isSorted(test2));
201+
System.out.println();
202+
203+
// Test Case 3: Reverse sorted array
204+
System.out.println("Test Case 3: Reverse Sorted Array");
205+
int[] test3 = {9, 7, 5, 3, 1};
206+
printArray("Original", test3);
207+
countingSort(test3);
208+
printArray("Sorted ", test3);
209+
System.out.println("Is sorted: " + isSorted(test3));
210+
System.out.println();
211+
212+
// Test Case 4: Array with duplicates
213+
System.out.println("Test Case 4: Array with Many Duplicates");
214+
int[] test4 = {5, 2, 8, 2, 9, 1, 5, 5};
215+
printArray("Original", test4);
216+
countingSort(test4);
217+
printArray("Sorted ", test4);
218+
System.out.println("Is sorted: " + isSorted(test4));
219+
System.out.println();
220+
221+
// Test Case 5: Single element
222+
System.out.println("Test Case 5: Single Element");
223+
int[] test5 = {42};
224+
printArray("Original", test5);
225+
countingSort(test5);
226+
printArray("Sorted ", test5);
227+
System.out.println("Is sorted: " + isSorted(test5));
228+
System.out.println();
229+
230+
// Test Case 6: All same elements
231+
System.out.println("Test Case 6: All Same Elements");
232+
int[] test6 = {7, 7, 7, 7, 7};
233+
printArray("Original", test6);
234+
countingSort(test6);
235+
printArray("Sorted ", test6);
236+
System.out.println("Is sorted: " + isSorted(test6));
237+
System.out.println();
238+
239+
// Test Case 7: Large numbers
240+
System.out.println("Test Case 7: Large Numbers");
241+
int[] test7 = {100, 50, 200, 75, 125};
242+
printArray("Original", test7);
243+
countingSort(test7);
244+
printArray("Sorted ", test7);
245+
System.out.println("Is sorted: " + isSorted(test7));
246+
System.out.println();
247+
248+
// Test Case 8: With zeros
249+
System.out.println("Test Case 8: Array with Zeros");
250+
int[] test8 = {0, 5, 0, 3, 0, 2};
251+
printArray("Original", test8);
252+
countingSort(test8);
253+
printArray("Sorted ", test8);
254+
System.out.println("Is sorted: " + isSorted(test8));
255+
System.out.println();
256+
257+
// Test Case 9: Negative numbers (using alternative method)
258+
System.out.println("Test Case 9: Array with Negative Numbers (Alternative Method)");
259+
int[] test9 = {-5, 2, -3, 8, 0, -1, 4};
260+
printArray("Original", test9);
261+
countingSortWithNegatives(test9);
262+
printArray("Sorted ", test9);
263+
System.out.println("Is sorted: " + isSorted(test9));
264+
System.out.println();
265+
266+
// Test Case 10: Error handling
267+
System.out.println("Test Case 10: Error Handling (Negative Numbers)");
268+
try {
269+
int[] test10 = {5, -3, 8, 2};
270+
printArray("Attempting to sort", test10);
271+
countingSort(test10); // Should throw exception
272+
System.out.println("ERROR: Should have thrown exception!");
273+
} catch (IllegalArgumentException e) {
274+
System.out.println("Correctly caught exception: " + e.getMessage());
275+
}
276+
System.out.println();
277+
278+
System.out.println("=== All tests completed successfully! ===");
279+
}
280+
}

0 commit comments

Comments
 (0)