Skip to content

Commit acf1090

Browse files
Merge branch 'master' into fix/fibonacci-search-out-of-bounds
2 parents 0e64954 + 55f551b commit acf1090

4 files changed

Lines changed: 95 additions & 2 deletions

File tree

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/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/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)