-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSortingAlgos.java
345 lines (330 loc) · 10.9 KB
/
SortingAlgos.java
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/**
* This class contains the following Sorting Methods
* - Selection Sort
* - Bubble Sort
* - Insertion Sort
* - Merge Sort
* - Quick Sort
* - Shell Sort
*/
import java.util.Arrays;
public class SortingAlgos {
/**
* Selection Sort:
*
* Approach:
*
* In selection sort, we pick the smallest element and swap it with the first
* element. Then we pick the second smallest element and swap it with the second
* element, and so on. We repeat this process until the entire array is sorted.
*
* Algorithm:
*
* repeat(numOfElements - 1) times
* set the first unsorted element as the minimum
* for each of the unsorted elements
* if element < currentMinimum
* set element as new minimum
* swap minimum with first unsorted position
*
* No. of Comparisons:
*
* The number of comparisons made by the selection sort algorithm is:
* (n-1) in the first pass, (n-2) in the second pass, (n-3) in the third pass up until 1 comparison in the last pass.
*
* Total Comparisons = (n-1) + (n-2) + (n-3) + ... + 1 = n(n-1)/2
*
* Max No. of Exchanges:
*
* The maximum number of exchanges made by the selection sort algorithm is n-1.
* Why? Because in the worst case, the smallest element is at the end of the array and we need to swap it with the first element.
*
* Time Complexity:
*
* The time complexity of the selection sort algorithm is O(n^2).
*/
public static void selectionSort(int[] arr) {
for(int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for(int j = i+1; j < arr.length; j++) {
if(arr[j] < arr[minIndex])
minIndex = j;
}
if(minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
/**
* Bubble Sort
*
* Approach:
*
* Bubble Sort repeatedly steps through the list, compares adjacent items, and swaps them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which means the list is sorted.
*
* Algorithm:
*
* repeat(numOfElements - 1) times
* for each of the unsorted elements
* if element > nextElement
* swap element with nextElement
*
* No. of Comparisons:
*
* The number of comparisons made by the bubble sort algorithm is:
* (n-1) in the first pass, (n-2) in the second pass, (n-3) in the third pass up until 1 comparison in the last pass.
* So the total number of comparisons is n(n-1)/2.
*
* No. of Exchanges:
*
* The maximum number of exchanges made by the bubble sort algorithm is n(n-1)/2.
*/
public static void bubbleSort(int[] arr,int n) {
for(int i = 0; i < n-1; i++) {
boolean isSorted = true;
for(int j = 0; j < n-i-1; j++) {
if(arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
isSorted = false;
}
}
if(isSorted)
break;
}
}
/**
* Insertion Sort
*
* Approach:
* In Insertion Sort, we divide the array into two parts: sorted and unsorted. We pick an element from the unsorted array and place it in its correct position in the sorted array.
*
* Algorithm:
*
* for i = 1 to n-1
* set current element as key
* set j as i-1
* while j >= 0 and arr[j] > key
* move elements of arr[j] to one position ahead
* decrement j
* set key to its correct position
*
* No. of comparisons: (n-1) + (n-2) + ... + 1 = n*(n-1)/2 Why? In insertion sort, we compare each element with the elements to its left to find the correct position, leading to n*(n-1)/2 comparisons.
*
* No. of exchanges: 0 to n-1 Why? In insertion sort, the number of exchanges depends on the initial order of the elements. In the best-case scenario, where the elements are already sorted, there are 0 exchanges. In the worst-case scenario, where the elements are in reverse order, there are n-1 exchanges.
*/
public static void insertionSort(int[] arr, int n) {
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];
j--;
}
arr[j+1] = key;
}
}
/**
* Merge Sort
*
* Approach:
*
* Merge Sort is a divide and conquer algorithm. It divides the input array into two halves, calls itself for the two halves, and then merges the two sorted halves.
*
* Algorithm:
*
* if low < high
* set mid as (low + high) / 2
* call mergeSort for the first half
* call mergeSort for the second half
* merge the two halves
*
* No. of comparisons: n * log(n) Why? In merge sort, the number of comparisons is proportional to n multiplied by the logarithm of n due to the divide-and-conquer nature of the algorithm.
*
* No. of exchanges: n * log(n) Why? In merge sort, the number of exchanges is also proportional to n multiplied by the logarithm of n because of the merging step that combines the sorted subarrays.
*/
public static void mergeSort(int[] a, int low, int high) {
if(low < high) {
int mid = (int) Math.floor((low + high) / 2);
mergeSort(a, low, mid);
mergeSort(a, mid+1, high);
merge(a, low, mid, high);
}
}
/**
* Merge Operation for Merge Sort
*
* Approach:
* b[high-low+1] // store the merged array
* i = low, j = mid+1, k = 0
* while(i <= mid and j <= high)
* if a[i] < a[j] then
* b[k] = a[i]
* i++
* else
* b[k] = a[j]
* j++
* k++
* // copy the remaining elements of the first half
* while(i <= mid)
* b[k] = a[i]
* i++
*
* // copy the remaining elements of the second half
* while(j <= high)
* b[k] = a[j]
* j++
*
* // copy the merged array back to the original array
* for(i = 0; i < high-low+1; i++)
* a[low+i] = b[i]
*/
public static void merge(int[] a, int low, int mid, int high) {
int[] b = new int[high-low+1];
int i = low, j = mid+1, k = 0;
while(i <= mid && j <= high) {
if(a[i] < a[j]) {
b[k] = a[i];
i++;
} else {
b[k] = a[j];
j++;
}
k++;
}
while(i <= mid) {
b[k] = a[i];
i++;
k++;
}
while(j <= high) {
b[k] = a[j];
j++;
k++;
}
for(i = 0; i < high-low+1; i++) {
a[low+i] = b[i];
}
}
/**
* Quick Sort
*
* Approach:
*
* Quick Sort is a divide and conquer algorithm. It picks an element as a pivot and partitions the given array around the picked pivot.
*
* Algorithm:
*
* if low < high
* set pivot as partition(a, low, high)
* call quickSort for the first half
* call quickSort for the second half
*
* No. of comparisons: n * log(n) to n^2 Why? In quick sort, the number of comparisons ranges from n * log(n) to n^2, depending on the choice of pivot elements and partitioning strategy.
*
* No. of exchanges: O(n log n) Why? In quick sort, the number of exchanges is typically O(n log n) due to the partitioning and swapping of elements around the pivot.
*/
public static void quickSort(int[] a, int low, int high) {
if(low < high) {
int pivot = partition(a, low, high);
quickSort(a, low, pivot-1);
quickSort(a, pivot+1, high);
}
}
/**
* Partition function for Quick Sort
*
* Approach:
* pivot_element = a[low]
* j = low
* for i = low+1 to high
* if(a[i] < pivot_element)
* j++
* if(i != j)
* swap a[i] with a[j]
* pivot_point = j
* if(low != pivot_point)
* swap a[low] with a[pivot_point]
* return pivot_point
*/
public static int partition(int[] a, int low, int high) {
int pivotElement = a[low];
int j = low;
for(int i = low+1; i <= high; i++) {
if(a[i] < pivotElement) {
j++;
if(i != j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
int pivotPoint = j;
if(low != pivotPoint) {
int temp = a[low];
a[low] = a[pivotPoint];
a[pivotPoint] = temp;
}
return pivotPoint;
}
/**
* Shell Sort
*
* Approach:
*
* Shell Sort is an optimization of the Insertion Sort algorithm. It starts by sorting pairs of elements far apart from each other and progressively reduces the gap between elements to be compared.
*
* Algorithm:
*
* gap = floor(n/2)
* while(gap >= 1) do
* for i = gap to n do
* x = a[i]
* j = i
* while(j >= gap and a[j-gap] > x) do
* a[j] = a[j-gap]
* j = j - gap
* a[j] = x
* gap = floor(gap/2)
*/
public static void shellSort(int[] a, int n) {
int gap = (int) Math.floor(n/2);
while(gap >= 1) {
for(int i = gap; i < n; i++) {
int x = a[i];
int j = i;
while(j >= gap && a[j-gap] > x) {
a[j] = a[j-gap];
j = j - gap;
}
a[j] = x;
}
gap = (int) Math.floor(gap/2);
}
}
// Main Method for Testing
public static void main(String[] args) {
int[] arr = {5,4,3,2,1};
selectionSort(arr);
System.out.println(Arrays.toString(arr));
int[] arr2 = {5,4,3,2,1};
bubbleSort(arr2, arr2.length);
System.out.println(Arrays.toString(arr2));
int[] arr3 = {5,4,3,2,1};
insertionSort(arr3, arr3.length);
System.out.println(Arrays.toString(arr3));
int[] arr4 = {5,4,3,2,1};
mergeSort(arr4, 0, arr4.length-1);
System.out.println(Arrays.toString(arr4));
int[] arr5 = {5,4,3,2,1};
quickSort(arr5, 0, arr5.length-1);
System.out.println(Arrays.toString(arr5));
int[] arr6 = {5,4,3,2,1};
shellSort(arr6, arr6.length);
System.out.println(Arrays.toString(arr6));
}
}