Skip to content

Commit 7f11a4d

Browse files
authored
Merge branch 'master' into clustring
2 parents ef0e011 + 0b0f921 commit 7f11a4d

8 files changed

Lines changed: 147 additions & 5 deletions

File tree

.github/workflows/stale.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
pull-requests: write
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/stale@v10.4.0
14+
- uses: actions/stale@v11.0.0
1515
with:
1616
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution!'
1717
close-issue-message: 'Please reopen this issue once you have made the required changes. If you need help, feel free to ask in our [Discord](https://the-algorithms.com/discord) server or ping one of the maintainers here. Thank you for your contribution!'

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
<dependency>
113113
<groupId>com.puppycrawl.tools</groupId>
114114
<artifactId>checkstyle</artifactId>
115-
<version>13.8.0</version>
115+
<version>13.9.0</version>
116116
</dependency>
117117
</dependencies>
118118
</plugin>

src/main/java/com/thealgorithms/searches/ExponentialSearch.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public <T extends Comparable<T>> int find(T[] array, T key) {
4646
range = range * 2;
4747
}
4848

49-
return Arrays.binarySearch(array, range / 2, Math.min(range, array.length), key);
49+
// The candidate block is the inclusive index range [range / 2, range], so the
50+
// exclusive upper bound handed to binarySearch has to be range + 1.
51+
final int index = Arrays.binarySearch(array, range / 2, Math.min(range + 1, array.length), key);
52+
return index >= 0 ? index : -1;
5053
}
5154
}

src/main/java/com/thealgorithms/searches/FibonacciSearch.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public <T extends Comparable<T>> int find(T[] array, T key) {
6969
}
7070
}
7171

72-
if (fibMinus1 == 1 && array[offset + 1] == key) {
72+
if (fibMinus1 == 1 && offset + 1 < n && array[offset + 1].compareTo(key) == 0) {
7373
return offset + 1;
7474
}
7575

src/main/java/com/thealgorithms/searches/JumpSearch.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public <T extends Comparable<T>> int find(T[] array, T key) {
7373
int limit = blockSize;
7474
// Jumping ahead to find the block where the key may be located
7575
while (limit < length && key.compareTo(array[limit]) > 0) {
76-
limit = Math.min(limit + blockSize, length - 1);
76+
limit += blockSize;
7777
}
7878

7979
// Perform linear search within the identified block

src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,46 @@ void testExponentialSearchLargeArray() {
8181
int expectedIndex = 9999;
8282
assertEquals(expectedIndex, exponentialSearch.find(array, key), "The index of the last element should be 9999.");
8383
}
84+
85+
/**
86+
* An element sitting exactly on the doubling boundary used to be reported as missing, because
87+
* the binary search was handed {@code range} as its exclusive upper bound instead of
88+
* {@code range + 1}.
89+
*/
90+
@Test
91+
void testExponentialSearchElementOnRangeBoundary() {
92+
ExponentialSearch exponentialSearch = new ExponentialSearch();
93+
Integer[] array = {-25, -9, 8, 21};
94+
assertEquals(2, exponentialSearch.find(array, 8), "The index of the found element should be 2.");
95+
}
96+
97+
/**
98+
* Every element must be found regardless of the array length.
99+
*/
100+
@Test
101+
void testExponentialSearchFindsEveryElement() {
102+
ExponentialSearch exponentialSearch = new ExponentialSearch();
103+
for (int length = 1; length <= 50; length++) {
104+
Integer[] array = new Integer[length];
105+
for (int i = 0; i < length; i++) {
106+
array[i] = i * 2;
107+
}
108+
for (int i = 0; i < length; i++) {
109+
assertEquals(i, exponentialSearch.find(array, i * 2), "Element at index " + i + " should be found for length " + length + ".");
110+
}
111+
}
112+
}
113+
114+
/**
115+
* A missing key has to yield -1 rather than the negative insertion point that
116+
* {@link java.util.Arrays#binarySearch} returns.
117+
*/
118+
@Test
119+
void testExponentialSearchNotFoundReturnsMinusOne() {
120+
ExponentialSearch exponentialSearch = new ExponentialSearch();
121+
Integer[] array = {1, 3, 5, 7, 9, 11};
122+
assertEquals(-1, exponentialSearch.find(array, 4), "A key inside the range but absent should give -1.");
123+
assertEquals(-1, exponentialSearch.find(array, 0), "A key below the minimum should give -1.");
124+
assertEquals(-1, exponentialSearch.find(array, 12), "A key above the maximum should give -1.");
125+
}
84126
}

src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,53 @@ void testFibonacciSearchLargeArray() {
121121
int expectedIndex = 9999;
122122
assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The index of the last element should be 9999.");
123123
}
124+
125+
/**
126+
* A key greater than every element used to throw {@link ArrayIndexOutOfBoundsException},
127+
* because the final probe read {@code array[offset + 1]} without checking the bound.
128+
*/
129+
@Test
130+
void testFibonacciSearchKeyGreaterThanLastElement() {
131+
FibonacciSearch fibonacciSearch = new FibonacciSearch();
132+
for (int length = 1; length <= 50; length++) {
133+
Integer[] array = new Integer[length];
134+
for (int i = 0; i < length; i++) {
135+
array[i] = i;
136+
}
137+
assertEquals(-1, fibonacciSearch.find(array, length), "A key above the maximum should not be found for length " + length + ".");
138+
}
139+
}
140+
141+
/**
142+
* The final probe used reference equality, so a key that is equal but not identical to the
143+
* stored element was reported as missing. Values above 127 are outside the {@link Integer}
144+
* cache and therefore are not the same object as the boxed array element.
145+
*/
146+
@Test
147+
void testFibonacciSearchFindsEqualButNotIdenticalKey() {
148+
FibonacciSearch fibonacciSearch = new FibonacciSearch();
149+
Integer[] array = {10, 20, 300};
150+
assertEquals(2, fibonacciSearch.find(array, Integer.valueOf(300)), "The index of the found element should be 2.");
151+
152+
String[] words = {"a", "b", "c"};
153+
String equalButDistinct = new StringBuilder("c").toString();
154+
assertEquals(2, fibonacciSearch.find(words, equalButDistinct), "The index of the found element should be 2.");
155+
}
156+
157+
/**
158+
* Every element must be found regardless of the array length.
159+
*/
160+
@Test
161+
void testFibonacciSearchFindsEveryElement() {
162+
FibonacciSearch fibonacciSearch = new FibonacciSearch();
163+
for (int length = 1; length <= 50; length++) {
164+
Integer[] array = new Integer[length];
165+
for (int i = 0; i < length; i++) {
166+
array[i] = 1000 + i * 2;
167+
}
168+
for (int i = 0; i < length; i++) {
169+
assertEquals(i, fibonacciSearch.find(array, Integer.valueOf(1000 + i * 2)), "Element at index " + i + " should be found for length " + length + ".");
170+
}
171+
}
172+
}
124173
}

src/test/java/com/thealgorithms/searches/JumpSearchTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44

5+
import java.util.concurrent.TimeUnit;
56
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.api.Timeout;
68

79
/**
810
* Unit tests for the JumpSearch class.
@@ -91,4 +93,50 @@ void testJumpSearchLargeArrayNotFound() {
9193
Integer key = 999; // Key not present
9294
assertEquals(-1, jumpSearch.find(array, key), "The element should not be found in the array.");
9395
}
96+
97+
/**
98+
* A key greater than every element used to make the jumping loop spin forever, because the
99+
* cursor was clamped to the last index and therefore stopped advancing.
100+
*/
101+
@Test
102+
@Timeout(value = 5, unit = TimeUnit.SECONDS, threadMode = Timeout.ThreadMode.SEPARATE_THREAD)
103+
void testJumpSearchKeyGreaterThanLastElement() {
104+
JumpSearch jumpSearch = new JumpSearch();
105+
Integer[] array = {1, 2, 3, 4};
106+
assertEquals(-1, jumpSearch.find(array, 5), "A key above the maximum should not be found.");
107+
}
108+
109+
/**
110+
* The same regression across several lengths, since the jump size depends on the array length.
111+
*/
112+
@Test
113+
@Timeout(value = 5, unit = TimeUnit.SECONDS, threadMode = Timeout.ThreadMode.SEPARATE_THREAD)
114+
void testJumpSearchKeyGreaterThanLastElementForEveryLength() {
115+
JumpSearch jumpSearch = new JumpSearch();
116+
for (int length = 1; length <= 50; length++) {
117+
Integer[] array = new Integer[length];
118+
for (int i = 0; i < length; i++) {
119+
array[i] = i;
120+
}
121+
assertEquals(-1, jumpSearch.find(array, length), "A key above the maximum should not be found for length " + length + ".");
122+
}
123+
}
124+
125+
/**
126+
* Every element must be found regardless of the array length, including the ones that sit
127+
* exactly on a jump boundary.
128+
*/
129+
@Test
130+
void testJumpSearchFindsEveryElement() {
131+
JumpSearch jumpSearch = new JumpSearch();
132+
for (int length = 1; length <= 50; length++) {
133+
Integer[] array = new Integer[length];
134+
for (int i = 0; i < length; i++) {
135+
array[i] = i * 2;
136+
}
137+
for (int i = 0; i < length; i++) {
138+
assertEquals(i, jumpSearch.find(array, i * 2), "Element at index " + i + " should be found for length " + length + ".");
139+
}
140+
}
141+
}
94142
}

0 commit comments

Comments
 (0)