-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBucketSort.java
More file actions
202 lines (161 loc) · 6.63 KB
/
BucketSort.java
File metadata and controls
202 lines (161 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package Algorithms.Sorting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Srinvas Vadige, srinivas.vadige@gmail.com
* @since 21 Sept 2024
@TimeComplexity O(n+r) -> n = nums.length, r = range of nums == max-min+1 == Bucket size
@SpaceComplexity O(r)
Summary:
Step 1: Create buckets.
Step 2: Distribute elements.
Step 3: Sort each bucket.
Step 4: Merge all buckets.
*/
public class BucketSort {
public static void main(String[] args) {
int[] nums = {2, 0, 2, 1, 1, 0};
bucketSortForNonNegativesWithRange(nums);
System.out.println("bucketSortForNonNegativesWithRange => " + Arrays.toString(nums));
nums = new int[]{2, 0, 2, 1, 1, 0, -1, -500};
findKthLargestUsingMinMaxRangeBucketSort(nums);
System.out.println("findKthLargestUsingMinMaxRangeBucketSort => " + Arrays.toString(nums));
nums = new int[]{2, 0, 2, 1, 1, 0, -1, -500};
bucketSort(nums);
System.out.println("bucketSort => " + Arrays.toString(nums));
nums = new int[]{2, 0, 2, 1, 1, 0, -1, -500};
bucketSort2(nums);
System.out.println("bucketSort2 => " + Arrays.toString(nums));
}
public static void bucketSortForNonNegativesWithRange(int[] nums) {
int[] buckets = new int[nums.length]; //
for (int num : nums) {
buckets[num]++; // allocate the bucket for each num
}
int i = 0;
for (int j = 0; j < buckets.length; j++) {
for (int k = 0; k < buckets[j]; k++) {
nums[i++] = j;
}
}
}
/**
* @TimeComplexity O(n+r) -> n = nums.length, r = range of nums == max-min+1 == Bucket size
* @SpaceComplexity O(r)
*
* How's the Bucket Sort work with negative numbers?
* cause "num - minValue" will never be negative, it will always be >= 0
* So, we can use it as an index in the count array.
*
* NOTE:
* Java int range: Integer.MIN_VALUE to Integer.MAX_VALUE
* Minimum: -2³¹ = -2,147,483,648 ≈ −2 × 10⁹
* Maximum: 2³¹ − 1 = 2,147,483,647 ≈ 2 × 10⁹
*
* So, this bucketSort works when -10⁹ <= nums[i] <= 10⁹. Because if the range is more than that int[] will not be able to hold the values
*/
public static void findKthLargestUsingMinMaxRangeBucketSort(int[] nums) {
int minValue = Arrays.stream(nums).min().getAsInt();
int maxValue = Arrays.stream(nums).max().getAsInt();
int[] bucket = new int[maxValue - minValue + 1]; // bucket size
// bucket sort with dupes
for (int num : nums) {
bucket[num - minValue]++; // if num==-500 then num-minValue will be 0 and if num==2 then num-minValue will be 502
}
int i = nums.length - 1; // fill the nums[] in reverse order
for(int bucketIndex = bucket.length - 1; bucketIndex >= 0; bucketIndex--) { // descending order loop --- i.e num=bucketIndex+minValue is the largest number
if (bucket[bucketIndex] == 0) continue; // skip empty buckets
int num = bucketIndex + minValue;
int numCount = bucket[bucketIndex];
while (numCount-- > 0) {
nums[i--] = num; // fill the nums[] with sorted order
}
}
}
public static void bucketSortForNegativesWithRange(int[] nums) {
int[] buckets = new int[nums.length]; //
for (int num : nums) {
buckets[num + nums.length]++; // allocate the bucket for each num
}
int i = 0;
for (int j = 0; j < buckets.length; j++) {
for (int k = 0; k < buckets[j]; k++) {
nums[i++] = j - nums.length;
}
}
}
/**
* if the Integer.MIN_VALUE <= num <= Integer.MAX_VALUE
*
* @TimeComplexity Best/Average Case: O(n + k), where k is bucket count. And Worst Case: O(n²), if all elements fall into one bucket and a slow sort is used inside (like insertion sort).
* @SpaceComplexity O(n)
*/
public static void bucketSort(int[] arr) {
if (arr.length == 0) return;
// 1. Find maximum and minimum values in the array
int maxValue = arr[0];
int minValue = arr[0];
for (int num : arr) {
if (num > maxValue) maxValue = num;
if (num < minValue) minValue = num;
}
// 2. Create buckets and distribute elements
int bucketCount = (maxValue - minValue) / arr.length + 1; // k
@SuppressWarnings("unchecked")
List<Integer>[] buckets = new List[bucketCount];
for (int i = 0; i < bucketCount; i++) {
buckets[i] = new ArrayList<>();
}
// 3. Distribute elements into buckets
for (int num : arr) {
int bucketIndex = (num - minValue) / arr.length;
buckets[bucketIndex].add(num);
}
// 4. Sort individual buckets
for (List<Integer> bucket : buckets) {
Collections.sort(bucket);
}
// 5. Merge buckets back into original array
int index = 0;
for (List<Integer> bucket : buckets) {
for (int num : bucket) {
arr[index++] = num;
}
}
}
/**
* NOT WORKING
* Here tried to use int[] buckets instead of List<Integer>[], but it doesn't work
*/
public static void bucketSort2(int[] arr) {
if (arr.length == 0) return;
// Step 1: Find maximum and minimum values in the array
int maxValue = arr[0];
int minValue = arr[0];
for (int num : arr) {
if (num > maxValue) maxValue = num;
if (num < minValue) minValue = num;
}
// Step 2: Calculate range and shift value to handle negative values
int range = maxValue - minValue + 1; // +1 to include max value
int shift = Math.abs(minValue); // Make sure all values become positive
// Step 3: Initialize int[] array (buckets) to count occurrences
int bucketCount = (range / arr.length) + 1; // Calculate number of buckets
int[] buckets = new int[bucketCount];
// Step 4: Distribute elements into buckets (counting occurrences)
for (int num : arr) {
int bucketIndex = (num + shift) / arr.length; // Use shifted value to index
buckets[bucketIndex]++;
}
// Step 5: Rebuild the sorted array using bucket counts
int index = 0;
for (int i = 0; i < bucketCount; i++) {
while (buckets[i] > 0) {
arr[index++] = i * arr.length + minValue + shift;
buckets[i]--;
}
}
}
}