Skip to content

Commit 9b3481a

Browse files
author
Alex Klymenko
committed
feat: SpreadSort implementation
1 parent 5113101 commit 9b3481a

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
package com.thealgorithms.sorts;
2+
import java.util.Arrays;
3+
4+
/**
5+
* SpreadSort is a highly efficient sorting algorithm suitable for large datasets.
6+
* It distributes elements into buckets and recursively sorts these buckets.
7+
* This implementation is generic and can sort any array of elements that extend Comparable.
8+
*/
9+
public class SpreadSort implements SortAlgorithm {
10+
private static final int INSERTION_SORT_THRESHOLD = 16;
11+
private static final int INITIAL_BUCKET_CAPACITY = 16;
12+
private static final int MIN_BUCKETS = 2;
13+
14+
/**
15+
* Sorts an array using the SpreadSort algorithm.
16+
*
17+
* @param array the array to be sorted
18+
* @param <T> the type of elements in the array
19+
* @return the sorted array
20+
*/
21+
@Override
22+
public <T extends Comparable<T>> T[] sort(T[] array) {
23+
if (array.length == 0) {
24+
return array;
25+
}
26+
spreadSort(array, 0, array.length - 1);
27+
return array;
28+
}
29+
30+
/**
31+
* Internal method to sort an array segment using the SpreadSort algorithm.
32+
*
33+
* @param array the array to be sorted
34+
* @param left the left boundary of the segment
35+
* @param right the right boundary of the segment
36+
* @param <T> the type of elements in the array
37+
*/
38+
private <T extends Comparable<T>> void spreadSort(final T[] array, final int left, final int right) {
39+
if (left >= right) {
40+
return;
41+
}
42+
43+
// Base case for small segments
44+
if (right - left < INSERTION_SORT_THRESHOLD) {
45+
insertionSort(array, left, right);
46+
return;
47+
}
48+
49+
T min = findMin(array, left, right);
50+
T max = findMax(array, left, right);
51+
52+
if (min.equals(max)) {
53+
return; // All elements are the same
54+
}
55+
56+
int numBuckets = calculateNumBuckets(right - left + 1);
57+
final Bucket<T>[] buckets = createBuckets(numBuckets);
58+
59+
distributeElements(array, left, right, min, max, numBuckets, buckets);
60+
collectElements(array, left, buckets);
61+
}
62+
63+
/**
64+
* Finds the minimum element in the specified segment of the array.
65+
*
66+
* @param array the array to search
67+
* @param left the left boundary of the segment
68+
* @param right the right boundary of the segment
69+
* @param <T> the type of elements in the array
70+
* @return the minimum element
71+
*/
72+
private <T extends Comparable<T>> T findMin(final T[] array, final int left, final int right) {
73+
T min = array[left];
74+
for (int i = left + 1; i <= right; i++) {
75+
if (SortUtils.less(array[i], min)) {
76+
min = array[i];
77+
}
78+
}
79+
return min;
80+
}
81+
82+
/**
83+
* Finds the maximum element in the specified segment of the array.
84+
*
85+
* @param array the array to search
86+
* @param left the left boundary of the segment
87+
* @param right the right boundary of the segment
88+
* @param <T> the type of elements in the array
89+
* @return the maximum element
90+
*/
91+
private <T extends Comparable<T>> T findMax(final T[] array, final int left, final int right) {
92+
T max = array[left];
93+
for (int i = left + 1; i <= right; i++) {
94+
if (SortUtils.greater(array[i], max)) {
95+
max = array[i];
96+
}
97+
}
98+
return max;
99+
}
100+
101+
/**
102+
* Calculates the number of buckets needed based on the size of the segment.
103+
*
104+
* @param segmentSize the size of the segment
105+
* @return the number of buckets
106+
*/
107+
private int calculateNumBuckets(final int segmentSize) {
108+
int numBuckets = segmentSize / INSERTION_SORT_THRESHOLD;
109+
return Math.max(numBuckets, MIN_BUCKETS);
110+
}
111+
112+
/**
113+
* Creates an array of buckets.
114+
*
115+
* @param numBuckets the number of buckets to create
116+
* @param <T> the type of elements in the buckets
117+
* @return an array of buckets
118+
*/
119+
@SuppressWarnings("unchecked")
120+
private <T extends Comparable<T>> Bucket<T>[] createBuckets(final int numBuckets) {
121+
final Bucket<T>[] buckets = new Bucket[numBuckets];
122+
for (int i = 0; i < numBuckets; i++) {
123+
buckets[i] = new Bucket<>();
124+
}
125+
return buckets;
126+
}
127+
128+
/**
129+
* Distributes elements of the array segment into buckets.
130+
*
131+
* @param array the array to be sorted
132+
* @param left the left boundary of the segment
133+
* @param right the right boundary of the segment
134+
* @param min the minimum element in the segment
135+
* @param max the maximum element in the segment
136+
* @param numBuckets the number of buckets
137+
* @param buckets the array of buckets
138+
* @param <T> the type of elements in the array
139+
*/
140+
private <T extends Comparable<T>> void distributeElements(final T[] array, final int left, final int right, final T min, final T max, final int numBuckets, final Bucket<T>[] buckets) {
141+
final double range = max.compareTo(min);
142+
for (int i = left; i <= right; i++) {
143+
int bucketIndex = (int) ((array[i].compareTo(min) * numBuckets) / (range + 1));
144+
buckets[bucketIndex].add(array[i]);
145+
}
146+
}
147+
148+
/**
149+
* Collects elements from the buckets back into the array.
150+
*
151+
* @param array the array to be sorted
152+
* @param left the left boundary of the segment
153+
* @param buckets the array of buckets
154+
* @param <T> the type of elements in the array
155+
*/
156+
private <T extends Comparable<T>> void collectElements(final T[] array, final int left, final Bucket<T>[] buckets) {
157+
int index = left;
158+
for (Bucket<T> bucket : buckets) {
159+
if (bucket.size() > 0) {
160+
T[] bucketArray = bucket.toArray();
161+
spreadSort(bucketArray, 0, bucketArray.length - 1);
162+
for (T element : bucketArray) {
163+
array[index++] = element;
164+
}
165+
}
166+
}
167+
}
168+
169+
/**
170+
* Insertion sort implementation for small segments.
171+
*
172+
* @param array the array to be sorted
173+
* @param left the left boundary of the segment
174+
* @param right the right boundary of the segment
175+
* @param <T> the type of elements in the array
176+
*/
177+
private <T extends Comparable<T>> void insertionSort(final T[] array, final int left, final int right) {
178+
for (int i = left + 1; i <= right; i++) {
179+
T key = array[i];
180+
int j = i - 1;
181+
while (j >= left && SortUtils.greater(array[j], key)) {
182+
array[j + 1] = array[j];
183+
j--;
184+
}
185+
array[j + 1] = key;
186+
}
187+
}
188+
189+
/**
190+
* Bucket class to hold elements during sorting.
191+
*
192+
* @param <T> the type of elements in the bucket
193+
*/
194+
private static class Bucket<T extends Comparable<T>> {
195+
private T[] elements;
196+
private int size;
197+
198+
/**
199+
* Constructs a new bucket with initial capacity.
200+
*/
201+
@SuppressWarnings("unchecked")
202+
Bucket() {
203+
elements = (T[]) new Comparable[INITIAL_BUCKET_CAPACITY];
204+
size = 0;
205+
}
206+
207+
/**
208+
* Adds an element to the bucket.
209+
*
210+
* @param element the element to add
211+
*/
212+
void add(T element) {
213+
if (size == elements.length) {
214+
elements = Arrays.copyOf(elements, size * 2);
215+
}
216+
elements[size++] = element;
217+
}
218+
219+
/**
220+
* Returns the number of elements in the bucket.
221+
*
222+
* @return the size of the bucket
223+
*/
224+
int size() {
225+
return size;
226+
}
227+
228+
/**
229+
* Returns an array containing all elements in the bucket.
230+
*
231+
* @return an array containing all elements in the bucket
232+
*/
233+
@SuppressWarnings("unchecked")
234+
T[] toArray() {
235+
return Arrays.copyOf(elements, size);
236+
}
237+
}
238+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.thealgorithms.sorts;
2+
3+
public class SpreadSortTest extends SortingAlgorithmTest {
4+
5+
protected int getGeneratedArraySize() {
6+
return 1000;
7+
}
8+
9+
@Override
10+
SortAlgorithm getSortAlgorithm() {
11+
return new SpreadSort();
12+
}
13+
}

0 commit comments

Comments
 (0)