Skip to content

Commit eb69b9a

Browse files
authored
Merge branch 'main' into branch-binarySearchTree
2 parents 25d631b + 2753a1f commit eb69b9a

File tree

65 files changed

+2554
-2042
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2554
-2042
lines changed

build.gradle

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
1-
/*
2-
* This file was generated by the Gradle 'init' task.
3-
*
4-
* This is a general purpose Gradle build.
5-
* To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.3/samples
6-
*/
71
plugins {
82
id 'java'
93
id "com.adarshr.test-logger" version "3.2.0"
104
id "checkstyle"
115
}
126

13-
sourceSets {
14-
main {
15-
java {
16-
srcDirs = ['src/main/java', 'scripts']
17-
}
18-
}
7+
sourceSets.main.java.srcDirs += ['scripts']
8+
9+
checkstyle {
10+
toolVersion = '10.2'
1911
}
2012

2113
repositories {
@@ -32,9 +24,3 @@ java {
3224
languageVersion = JavaLanguageVersion.of(11)
3325
}
3426
}
35-
36-
checkstyle {
37-
def archive = configurations.checkstyle.resolve().find { it.name.startsWith("checkstyle") }
38-
config = resources.text.fromArchiveEntry(archive, "google_checks.xml")
39-
}
40-

config/checkstyle/checkstyle.xml

Lines changed: 374 additions & 0 deletions
Large diffs are not rendered by default.

scripts/scripts.iml

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/main/java/algorithms/sorting/countingSort/CountingSort.java

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,8 @@
22

33
/**
44
* <p></p> Stable implementation of Counting Sort.
5-
*
6-
* <p></p> Brief Description: <br>
7-
* Counting sort is a non-comparison based sorting algorithm and isn't bounded by the O(nlogn) lower-bound
8-
* of most sorting algorithms. <br>
9-
* It first obtains the frequency map of all elements (ie counting the occurrence of every element), then
10-
* computes the prefix sum for the map. This prefix map tells us which position an element should be inserted. <br>
11-
* Ultimately, each group of elements will be placed together, and the groups in succession, in the sorted output.
12-
*
13-
* <p></p> Assumption for use: <br>
14-
* To perform counting sort, the elements must first have total ordering and their rank must be known.
15-
*
16-
* <p></p> Implementation Invariant: <br>
17-
* At the end of the ith iteration, the ith element from the back will be placed in its rightful position.
18-
*
19-
* <p></p>
20-
* COMMON MISCONCEPTION: Counting sort does not require total ordering of elements since it is non-comparison based.
21-
* This is incorrect. It requires total ordering of elements to determine their relative positions in the sorted output.
22-
* In fact, in conventional implementation, the total ordering property is reflected by virtue of the structure
23-
* of the frequency map.
24-
*
25-
* <p></p> Complexity Analysis: <br>
26-
* Time: O(k+n)=O(max(k,n)) where k is the value of the largest element and n is the number of elements. <br>
27-
* Space: O(k+n)=O(max(k,n)) <br>
28-
* Counting sort is most efficient if the range of input values do not exceed the number of input values. <br>
29-
* Counting sort is NOT AN IN-PLACE algorithm. For one, it requires additional space to store freq map. <br>
30-
*
31-
* <p></p> Note: Implementation deals with integers but the idea is the same and can be generalised to other objects,
32-
* as long as what was discussed above remains true.
5+
* This non-comparison-based sorting algorithm is efficient for sorting integers with a small range.
6+
* For detailed explanation and complexity analysis, see README.
337
*/
348
public class CountingSort {
359
/**
@@ -40,7 +14,7 @@ public class CountingSort {
4014
public static int[] sort(int[] arr) {
4115
int k = 0;
4216
int n = arr.length;
43-
// Find the max. value in arr
17+
// Find the max. value in arr. This tells us the size of the freq map array.
4418
for (int i = 0; i < n; i++) {
4519
k = Math.max(k, arr[i]);
4620
}
@@ -53,11 +27,11 @@ public static int[] sort(int[] arr) {
5327
for (int i = 1; i < k+1; i++) {
5428
freq[i] += freq[i-1];
5529
}
56-
// Sort the array by placing in output array
30+
// Sort the array by placing element in the output array
5731
int[] sorted = new int[n];
58-
for (int i = arr.length-1; i >= 0; i--) { // Notice we start from the back to maintain stable property
32+
for (int i = arr.length-1; i >= 0; i--) { // we start from the back to maintain stable property
5933
int num = arr[i];
60-
sorted[freq[num]-1] = num;
34+
sorted[freq[num]-1] = num; // freq[num]-1 because 0-indexed
6135
freq[num]--;
6236
}
6337
return sorted;
Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
# Counting Sort
22

3+
## Background
34
Counting sort is a non-comparison-based sorting algorithm and isn't bounded by the O(nlogn) lower-bound
45
of most sorting algorithms. <br>
5-
It first obtains the frequency map of all elements (ie counting the occurrence of every element), then
6+
It first obtains the frequency map of all elements (i.e. counting the occurrence of every element), then
67
computes the prefix sum for the map. This prefix map tells us which position an element should be inserted.
7-
Ultimately, each group of elements will be placed together, and the groups in succession, in the sorted output.
8+
It is updated after each insertion to reflection the new position to insert the next time the same element is
9+
encountered. <br>
10+
11+
### Implementation Invariant
12+
At the end of the ith iteration, the ith element (of the original array) from the back will be placed in
13+
its correct position.
14+
15+
Note: An alternative implementation from the front is easily done with minor modification.
16+
The catch is that this implementation is not stable.
17+
18+
### Common Misconception
19+
_Counting sort does not require total ordering of elements since it is non-comparison based._
20+
21+
This is incorrect. It requires total ordering of elements to determine their relative positions in the sorted output.
22+
In our implementation, the total ordering property is reflected by virtue of the structure of the frequency map.
823

924
## Complexity Analysis
10-
Time: O(k+n)=O(max(k,n)) where k is the value of the largest element and n is the number of elements. <br>
11-
Space: O(k+n)=O(max(k,n)) <br>
25+
**Time**: O(k+n)=O(max(k,n)) <br>
26+
**Space**: O(k+n)=O(max(k,n)) <br>
27+
where k is the value of the largest element and n is the number of elements.
28+
1229
Counting sort is most efficient if the range of input values do not exceed the number of input values. <br>
1330
Counting sort is NOT AN IN-PLACE algorithm. For one, it requires additional space to store freq map. <br>
1431

1532
## Notes
16-
COMMON MISCONCEPTION: Counting sort does not require total ordering of elements since it is non-comparison based.
17-
This is incorrect. It requires total ordering of elements to determine their relative positions in the sorted output.
18-
In fact, in conventional implementation, the total ordering property is reflected by virtue of the structure
19-
of the frequency map.
20-
21-
Supplementary: Here is a [video](https://www.youtube.com/watch?v=OKd534EWcdk) if you are still having troubles.
33+
1. Counting sort (stable version) is often used as a sub-routine for radix sort.
34+
2. Supplementary: Here is a [video](https://www.youtube.com/watch?v=OKd534EWcdk) if you are still having troubles.
Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
# Cyclic Sort
2-
Cyclic sort is a comparison-based, in-place algorithm that performs sorting in O(n^2) time.
3-
It is quite similar to selection sort, with both invariants ensuring that at the end of
4-
the ith iteration, the ith element is correctly positioned. But they differ slightly in how
5-
they ensure this invariant is maintained, allowing cyclic sort to have a time complexity of O(n)
6-
for certain inputs (the relative ordering of the elements are already known).
2+
3+
## Background
4+
Cyclic sort is a comparison-based, in-place algorithm that performs sorting (generally) in O(n^2) time.
5+
Though under some conditions (discussed later), the best case could be done in O(n) time.
6+
7+
### Implementation Invariant
8+
At the end of the ith iteration, the ith element
9+
(of the original array, from either the back or front depending on implementation), is correctly positioned.
10+
11+
### Comparison to Selection Sort
12+
Its invariant is quite similar as selection sort's. But they differ slightly in maintaining this invariant.
13+
The algorithm for cyclic sort does a bit more than selection sort's.
14+
In the process of trying to find the correct element for the ith position, any element that was
15+
encountered will be correctly placed in their positions as well.
16+
17+
This allows cyclic sort to have a time complexity of O(n) for certain inputs.
18+
(where the relative ordering of the elements is already known). This is discussed in the [**simple**](./simple) case.
19+
20+
## Simple and Generalised Case
21+
We discuss more implementation-specific details and complexity analysis in the respective folders. In short,
22+
1. The [**simple**](./simple) case discusses the non-comparison based implementation of cyclic sort under
23+
certain conditions. This allows the best case to be better than O(n^2).
24+
2. The [**generalised**](./generalised) case discusses cyclic sort for general inputs. This is comparison-based and is
25+
usually implemented in O(n^2).
26+
27+
Lines changed: 11 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,33 @@
11
package algorithms.sorting.cyclicSort.generalised;
22
/**
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.
394
*/
405
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++) {
438
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
7213
if (arr[i] < currElement) {
7314
rightfulPos++;
7415
}
7516
}
76-
if (currIdx == rightfulPos) {
77-
break;
78-
}
79-
while (currElement == arr[rightfulPos]) {
17+
while (currElement == arr[rightfulPos]) { // duplicates found, so find next suitable position
8018
rightfulPos++;
8119
}
82-
tmp = currElement;
20+
int tmp = currElement; // swap, put item in its rightful position
8321
arr[currIdx] = arr[rightfulPos];
8422
arr[rightfulPos] = tmp;
85-
}
23+
} while (rightfulPos != currIdx);
8624
}
8725
}
8826

8927
/*
9028
Overloaded helper method that calls internal implementation.
9129
*/
9230
public static void sort(int[] arr) {
93-
cycleSort(arr, arr.length);
31+
cyclicSort(arr, arr.length);
9432
}
9533
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Generalized Case
2+
3+
## More Details
4+
Implementation of cyclic sort in the generalised case where the input can contain any integer and duplicates.
5+
6+
This is a comparison-based algorithm. In short, for the element encountered at the ith position of the original array,
7+
the algorithm does a O(n) traversal to search for its rightful position and does a swap. It repeats this until a swap
8+
placing the correct element at the ith position, before moving onto the next (i+1)th.
9+
10+
### Illustration
11+
Result: 6 10 6 5 7 4 2 1 <br> &nbsp;
12+
Read: ^ 6 should be placed at index 4, so we do a swap with 6 and 7, <br><br>
13+
Result: 7 10 6 5 6 4 2 1 <br> &nbsp;
14+
Read: ^ 7 should be placed at index 6, so we do a swap. Note that index 5 should be taken up by dup 6 <br><br>
15+
Result: 2 10 6 5 6 4 7 1 <br> &nbsp;
16+
Read: ^ 2 should be placed at index 1, so swap. <br><br>
17+
Result: 10 2 6 5 6 4 7 1 <br> &nbsp;
18+
Read: ^ 10 is the largest, should be placed at last index, so swap. <br><br>
19+
Result: 1 2 6 5 6 4 7 10 <br> &nbsp;
20+
Read: ^ Correctly placed, so move on. Same for 2. <br> &nbsp;
21+
Read: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
22+
^ 6 should be placed at index 4. But index 4 already has a 6. So place at index 5 and so on. <br><br>
23+
Result: 1 2 4 5 6 6 7 10 <br> &nbsp;
24+
Read: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
25+
^ ^ ^ ^ ^ Continue with O(n) verification of correct position at each iteration
26+
27+
28+
## Complexity Analysis
29+
**Time**:
30+
- Best: O(n^2) even if the ith element is encountered in the ith position, a O(n) traversal validation check is needed
31+
- Worst: O(n^2) since we need O(n) time to find / validate the correct position of an element and
32+
the total number of O(n) traversals is bounded by O(n).
33+
- Average: O(n^2), it's bounded by the above two
34+
35+
**Space**: O(1) auxiliary space, this is an in-place algorithm

src/main/java/algorithms/sorting/cyclicSort/simple/CyclicSort.java

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,7 @@
22

33
/**
44
* Implementation of cyclic sort in the simple case where the n elements of the given array are contiguous,
5-
* but not in sorted order. Below illustrates the idea using integers from 0 to n-1. <p></p>
6-
*
7-
* Analysis: <br>
8-
* Time:
9-
* Best: O(n) since the array has to be traversed <br>
10-
* Worst: O(n) since each element is at most seen twice <br>
11-
* Average: O(n), it's bounded by the above two <br>
12-
* Space: O(1) auxiliary space, this is an in-place algorithm <p></p>
13-
*
14-
* Invariant: <br>
15-
* At the end of the ith iteration, the ith element is correctly positioned
16-
* (smallest or largest depending on implementation). <br>
17-
*
18-
* This is exactly the same invariant as Selection sort. But the algorithm for cyclic sort actually does a bit
19-
* more. In the process of trying to find the correct element for the ith position, whatever elements that were
20-
* encountered will be correctly placed in their positions as well. This leads to the O(n) complexity as
21-
* opposed to Selection sort's O(n^2). <p></p>
22-
*
23-
* NOTE: <br>
24-
* In this implementation, the algorithm is not comparison-based! (unlike the general case) <br>
25-
* It makes use of the known inherent ordering of the numbers. <br>
26-
*
27-
* It may seem quite trivial to sort integers from 0 to n-1 when one could simply generate such a sequence. But
28-
* this algorithm proves its use in cases where the integers to be sorted are keys to associated values and sorting
29-
* to be done in O(1) auxiliary space.
5+
* but not in sorted order. Below illustrates the idea using integers from 0 to n-1.
306
*/
317
public class CyclicSort {
328
/**
@@ -38,12 +14,12 @@ public static void sort(int[] arr) {
3814
while (curr < arr.length) { // iterate until the end of the array
3915
int ele = arr[curr]; // encounter an element that may not be in its correct position
4016
assert ele >= 0 && ele < arr.length : "Input array should only have integers from 0 to n-1 (inclusive)";
41-
if (ele != curr) { // verified that it is indeed not the correct element to be placed at this curr position
17+
if (ele != curr) { // verified that it is indeed not the correct element to be placed at curr position
4218
int tmp = arr[ele]; // go to the correct position of ele
4319
arr[ele] = ele; // do a swap
4420
arr[curr] = tmp; // note that curr isn't incremented because we haven't yet placed the correct element
4521
} else {
46-
curr += 1; // we found the correct element to be placed at pos curr, which in this example, is itself
22+
curr += 1; // found the correct element to be placed at curr, which in this eg, is itself, so, increment
4723
}
4824
}
4925
}

0 commit comments

Comments
 (0)