|
1 | 1 | package algorithms.sorting.cyclicSort.generalised;
|
2 | 2 | /**
|
3 |
| - * Implementation of cyclic sort in the generalised case where the input can contain any integer and even duplicates. |
4 |
| - * <p></p> |
5 |
| - * |
6 |
| - * Analysis: <br> |
7 |
| - * Time: |
8 |
| - * Best: O(n^2) even though no swaps, array still needs to be traversed in O(n) at each iteration <br> |
9 |
| - * Worst: O(n^2) since we need O(n) time to find the correct position of an element at each iteration <br> |
10 |
| - * Average: O(n^2) |
11 |
| - * Space: O(1) auxiliary space, this is an in-place algorithm <p></p> |
12 |
| - * |
13 |
| - * Invariant: <br> |
14 |
| - * At the end of the ith iteration, the ith element is correctly positioned |
15 |
| - * (smallest or largest depending on implementation). <br> |
16 |
| - * |
17 |
| - * This is exactly the same invariant as Selection sort. But the algorithm for cyclic sort actually does a bit |
18 |
| - * more. In the process of trying to find the correct element for the ith position, whatever elements that were |
19 |
| - * encountered will be correctly placed in their positions as well. Though, unlike the simple case where the |
20 |
| - * ordering of the elements are known between one another, the time complexity here remains at O(n^2) because |
21 |
| - * cyclic sort will still have to iterate over all the elements at each iteration to verify or find the correct |
22 |
| - * position of the element. <p></p> |
23 |
| - * |
24 |
| - * Illustration: <br> |
25 |
| - * Result: 6 10 6 5 7 4 2 1 |
26 |
| - * Read: ^ 6 should be placed at index 4, so we do a swap, |
27 |
| - * Result: 7 10 6 5 6 4 2 1 |
28 |
| - * Read: ^ 7 should be placed at index 6, so we do a swap. Note that index 5 should be taken up by dup 6 |
29 |
| - * Result: 2 10 6 5 6 4 7 1 |
30 |
| - * Read: ^ 2 should be placed at index 1, so swap. |
31 |
| - * Result: 10 2 6 5 6 4 7 1 |
32 |
| - * Read: ^ 10 is the largest, should be placed at last index, so swap. |
33 |
| - * Result: 1 2 6 5 6 4 7 10 |
34 |
| - * Read: ^ Correctly placed, so move on. Same for 2. |
35 |
| - * Read: ^ should be placed at index 4. But index 4 already has a 6. So place at index 5 and so on. |
36 |
| - * Result: 1 2 4 5 6 6 7 10 |
37 |
| - * Read: ^ ^ ^ ^ ^ Continue with O(n) verification of correct position at each iteration |
38 |
| - * |
| 3 | + * Implementation of cyclic sort in the generalised case where the input can contain any integer and duplicates. |
39 | 4 | */
|
40 | 5 | public class CyclicSort {
|
41 |
| - public static void cycleSort(int[] arr, int n) { |
42 |
| - for (int currIdx = 0; currIdx < n - 1; currIdx++) { |
| 6 | + public static void cyclicSort(int[] arr, int n) { |
| 7 | + for (int currIdx = 0; currIdx < n-1; currIdx++) { |
43 | 8 | int currElement = arr[currIdx];
|
44 |
| - int rightfulPos = currIdx; |
45 |
| - for (int i = currIdx + 1; i < n; i++) { // O(n), find the rightful position of the curr element |
46 |
| - if (arr[i] < currElement) { |
47 |
| - rightfulPos++; |
48 |
| - } |
49 |
| - } |
50 |
| - if (rightfulPos == currIdx) { // verified currElement is already in its right position, go to next index |
51 |
| - continue; |
52 |
| - } |
53 |
| - |
54 |
| - while (currElement == arr[rightfulPos]) { // when attempting to place currElement at rightful pos, |
55 |
| - rightfulPos++; // found that currElement is a duplicate, so place duplicates at next immediate positions |
56 |
| - } |
57 |
| - |
58 |
| - int tmp = currElement; // swap, put item in its rightful position |
59 |
| - arr[currIdx] = arr[rightfulPos]; |
60 |
| - arr[rightfulPos] = tmp; |
61 |
| - |
62 |
| - /* |
63 |
| - The currElement has now been placed at its right position, with the element previously at that position |
64 |
| - at currIdx now. We shall continue this process until the element being swapped and placed at currIdx is the |
65 |
| - correct one. In other words, the rightfulPos of the element to be considered is the same as currIdx. |
66 |
| - Only then will we move on to the next index. |
67 |
| - */ |
68 |
| - while (currIdx != rightfulPos) { |
69 |
| - currElement = arr[currIdx]; |
70 |
| - rightfulPos = currIdx; |
71 |
| - for (int i = currIdx + 1; i < n; i++) { |
| 9 | + int rightfulPos; |
| 10 | + do { |
| 11 | + rightfulPos = currIdx; // initialization since elements before currIdx are correctly placed |
| 12 | + for (int i = currIdx + 1; i < n; i++) { // O(n) find rightfulPos for the currElement |
72 | 13 | if (arr[i] < currElement) {
|
73 | 14 | rightfulPos++;
|
74 | 15 | }
|
75 | 16 | }
|
76 |
| - if (currIdx == rightfulPos) { |
77 |
| - break; |
78 |
| - } |
79 |
| - while (currElement == arr[rightfulPos]) { |
| 17 | + while (currElement == arr[rightfulPos]) { // duplicates found, so find next suitable position |
80 | 18 | rightfulPos++;
|
81 | 19 | }
|
82 |
| - tmp = currElement; |
| 20 | + int tmp = currElement; // swap, put item in its rightful position |
83 | 21 | arr[currIdx] = arr[rightfulPos];
|
84 | 22 | arr[rightfulPos] = tmp;
|
85 |
| - } |
| 23 | + } while (rightfulPos != currIdx); |
86 | 24 | }
|
87 | 25 | }
|
88 | 26 |
|
89 | 27 | /*
|
90 | 28 | Overloaded helper method that calls internal implementation.
|
91 | 29 | */
|
92 | 30 | public static void sort(int[] arr) {
|
93 |
| - cycleSort(arr, arr.length); |
| 31 | + cyclicSort(arr, arr.length); |
94 | 32 | }
|
95 | 33 | }
|
0 commit comments