|
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