Skip to content

Commit 2e579e9

Browse files
committed
Merge branch 'main' into branch-Gradle
2 parents 56f1e97 + c063f10 commit 2e579e9

File tree

5 files changed

+244
-0
lines changed

5 files changed

+244
-0
lines changed

assets/BinarySearch.png

176 KB
Loading
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package src.algorithms.searches.binarySearch;
2+
3+
/** Here, we are implementing BinarySearch where we search an array for a target value at O(log n) time complexity.
4+
*
5+
* Assumptions:
6+
* The array is sorted in ascending order.
7+
* All elements in the array are unique. (to allow for easy testing)
8+
*
9+
* Brief Description and Implementation Invariant:
10+
* With the assumption that the array is sorted in ascending order, BinarySearch reduces the search range by half or
11+
* half + 1 (due to floor division) after every loop. This is done by reassigning the max (high) or min (low) of the
12+
* search range to the middle of the search range when the target value is smaller than or larger than the current
13+
* middle value respectively, and continuing the search thereafter.
14+
*
15+
* In both scenarios where the target is not equal to arr[mid], the high and low pointers are reassigned mid decremented
16+
* /incremented by 1. This ensures that there will never be an infinite loop as the search range will no longer include
17+
* the mid-value, causing the search range to constantly "shrink". We know we can decrement/increment mid by 1 during
18+
* the reassignment as the mid-value is definitely not the target and should no longer be in the search range.
19+
*
20+
* At the end of every loop, we know that the target value is either within the search range or does not exist in the
21+
* array, thereby ensuring the correctness of the algorithm.
22+
*
23+
* Since after each iteration, the search range is halved, it will only take a maximum of O(log n) times before the
24+
* target is either found or determined to not exist in the array.
25+
*/
26+
public class BinarySearch {
27+
/**
28+
* Searches for a target value within a sorted array using the binary search algorithm.
29+
* @param arr the sorted array in which the search is to be performed.
30+
* @param target the value to be searched for.
31+
* @return the index of the target if found, otherwise -1.
32+
*/
33+
public static int search(int[] arr, int target) {
34+
int high = arr.length - 1; // max index is 3 if array length is 4
35+
int low = 0;
36+
while (low <= high) { // When low == high, arr[low] can still == target, therefore should still check
37+
int mid = low + (high - low) / 2; // equivalent to high + low / 2 but reduces cases of integer overflow
38+
if (arr[mid] > target) {
39+
high = mid - 1; // -1 since current mid is not == target and should not be in the search range anymore
40+
} else if (arr[mid] < target) {
41+
low = mid + 1; // +1 since current mid is not == target and should not be in the search range anymore
42+
} else {
43+
return mid;
44+
}
45+
}
46+
47+
return -1;
48+
}
49+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package src.algorithms.searches.binarySearch;
2+
3+
/** Here, we are implementing BinarySearchTemplated where we search an array for a target value at O(log n) time
4+
* complexity.
5+
*
6+
* Assumptions:
7+
* The array is sorted in ascending order.
8+
* All elements in the array are unique. (to allow for easy testing)
9+
*
10+
* Brief Description and Implementation Invariant:
11+
* With the assumption that the array is sorted in ascending order, BinarySearchTemplated reduces the search range by
12+
* half or half + 1 (due to floor division) after every loop. This is done by reassigning the max (high) or min (low) of
13+
* the search range to the middle of the search range when the target value is smaller than or larger than the current
14+
* middle value respectively, and continuing the search thereafter.
15+
*
16+
* In this version, there is no condition to check if the current mid is equal to the target to prematurely end the
17+
* search. Hence, the only way for the loop to complete is when low exceeds high.
18+
*
19+
* At the end of every loop, we know that the target value is either within the search range or does not exist in the
20+
* array, thereby ensuring the correctness of the algorithm.
21+
*
22+
* Since after each iteration, the search range is halved, it will only take a maximum of O(log n) times before the
23+
* target is either found or determined to not exist in the array.
24+
*/
25+
public class BinarySearchTemplated {
26+
/**
27+
* A utility method to compare two integers.
28+
* @param value The current value from the array.
29+
* @param target The value being searched for.
30+
* @return true if the current value is less than the target, otherwise false.
31+
*/
32+
// The condition should be changed accordingly
33+
public static boolean condition(int value, int target) {
34+
return value >= target;
35+
}
36+
37+
/**
38+
* Conducts a binary search to find the target within the sorted array.
39+
*
40+
* @param arr The sorted input array.
41+
* @param target The value to be searched within the array.
42+
* @return The index of the target value if found, otherwise -1.
43+
*/
44+
public static int search(int[] arr, int target) {
45+
// The search space i.e. high and low should be changed accordingly.
46+
int high = arr.length - 1; // max index is 3 if array length is 4
47+
int low = 0;
48+
while (low < high) {
49+
int mid = low + (high - low) / 2; // equivalent to high + low / 2 but reduces cases of integer overflow
50+
if (condition(arr[mid], target)) { // if value >= target
51+
high = mid;
52+
} else { // if value < target
53+
low = mid + 1;
54+
}
55+
}
56+
57+
// Checks if low value is indeed the target
58+
// Note that the following checks may not be required in other use cases of this template
59+
if (low < arr.length && arr[low] == target) {
60+
// returned value should be changed accordingly (low or low - 1)
61+
return low;
62+
}
63+
// Returns -1 if loop was exited without finding the target
64+
return -1;
65+
}
66+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Binary Search
2+
Binary search is a search algorithm that finds the position of a target value within a sorted array or list. It compares
3+
the target value to the middle element of the search range, then, based on the comparison, narrows the search to the
4+
upper or lower half of the current search range.
5+
6+
Two versions of binary search has been implemented in this repository - BinarySearch and BinarySearchTemplated.
7+
8+
## BinarySearch
9+
![binary search img](../../../../assets/BinarySearch.png)
10+
Image Source: GeeksforGeeks
11+
12+
BinarySearch is a more straightforward and intuitive version of the binary search algorithm. In this approach, after the
13+
mid-value is calculated, the high and low pointers are adjusted by just one unit. From the above example, after mid
14+
points to index 4 in the first search, the low pointer moves to index 5 (+1) when narrowing the search. Similarly, when
15+
mid points to index 7 in the second search, the high pointer shifts to index 6 (-1) when narrowing the search. This
16+
prevents any possibility of infinite loops.
17+
18+
## BinarySearchTemplated
19+
20+
BinarySearchTemplated removes the condition that checks if the current mid-value is equal to the target (which helps to
21+
end the search the moment the target is found). The template adds a "condition" method which will be modified based on
22+
the requirements of the implementation.
23+
24+
The narrowing of the search space differs from BinarySearch - only one of the high or low pointers will be adjusted by
25+
one unit.
26+
27+
This template will work for most binary search problems and will only require the following changes:
28+
- Search space (high and low)
29+
- Condition method
30+
- Returned value (low or low - 1)
31+
32+
### Search Space (Requires change)
33+
Simply modify the initialisation of the high and low pointer according to the search space.
34+
35+
### Condition (Requires change)
36+
We assume that when the condition returns true, the current value "passes" and when the condition returns false, the
37+
current value "fails".
38+
39+
In this template, we want to find the first "pass" in the array.
40+
41+
INSERT IMAGE OF FIRST PASS
42+
43+
### Returned Value (Requires change)
44+
In the implementation of BinarySearchTemplated, return low was used to find the first "pass".
45+
46+
EXPLANATION TBC, STILL THINKING HOW TO PHRASE IT.
47+
48+
### Search Space Adjustment
49+
What should be the search space adjustment? (Why only low = mid + 1)
50+
51+
Due to the nature of floor division in Java's \ operator, the searched mid-index will always be smaller than the high
52+
pointer of the previous search range. On the other hand, low = mid + 1, ensures that the searched mid-index is always
53+
larger than the low pointer of the previous search range. This ensures that the search range is narrowed in every loop
54+
and prevents the possibility of infinite loops.
55+
56+
INSERT IMAGE HERE TO EXPLAIN
57+
58+
As we close in towards the target value, the final low = mid + 1 narrows the search range from low. TBC ON EXPLANATION
59+
60+
Credits: [Powerful Ultimate Binary Search Template](https://leetcode.com/discuss/general-discussion/786126/python-powerful-ultimate-binary-search-template-solved-many-problems)
61+
62+
## Complexity Analysis
63+
**Time**:
64+
- Worst case: O(log n)
65+
- Average case: O(log n)
66+
- Best case:
67+
- BinarySearch O(1)
68+
- BinarySearchTemplated O(log n)
69+
70+
BinarySearch:
71+
In the worst case, the target is either in the first index or does not exist in the array at all.
72+
In the best case, the target is the middle (odd number of element) or the first middle element (even number of elements)
73+
if floor division is used to determine the middle.
74+
75+
BinaryTemplated:
76+
In all cases, O(log n) iterations will be required as there is no condition to exit the loop prematurely.
77+
78+
**Space**: O(1) since no new data structures are used and searching is only done within the array given
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package test.algorithms.binarySearchTest;
2+
3+
import org.junit.Test;
4+
5+
import src.algorithms.searches.binarySearch.BinarySearchTemplated;
6+
import src.algorithms.searches.binarySearch.BinarySearch;
7+
8+
import java.util.Arrays;
9+
10+
import static org.junit.Assert.assertArrayEquals;
11+
import static org.junit.Assert.assertEquals;
12+
13+
public class BinarySearchTest {
14+
@Test
15+
public void test_binarySearch() {
16+
// Test 1: even number of elements
17+
int[] firstArray = {1, 5, 10, 12};
18+
int firstResult = BinarySearch.search(firstArray, 1);
19+
20+
// Test 2: odd number of elements
21+
int[] secondArray = {1, 5, 10, 11, 12};
22+
int secondResult = BinarySearch.search(secondArray, 11);
23+
24+
// Test 3: target not in array
25+
int[] thirdArray = {1, 5, 10, 11, 12};
26+
int thirdResult = BinarySearch.search(thirdArray, 3);
27+
28+
assertEquals(0, firstResult);
29+
assertEquals(3, secondResult);
30+
assertEquals(-1, thirdResult);
31+
}
32+
33+
@Test
34+
public void test_binarySearchTemplated() {
35+
// Test 1: even number of elements
36+
int[] firstArray = {1, 5, 10, 12};
37+
int firstResult = BinarySearchTemplated.search(firstArray, 1);
38+
39+
// Test 2: odd number of elements
40+
int[] secondArray = {1, 5, 10, 11, 12};
41+
int secondResult = BinarySearchTemplated.search(secondArray, 11);
42+
43+
// Test 3: target not in array
44+
int[] thirdArray = {1, 5, 10, 11, 12};
45+
int thirdResult = BinarySearchTemplated.search(thirdArray, 3);
46+
47+
assertEquals(0, firstResult);
48+
assertEquals(3, secondResult);
49+
assertEquals(-1, thirdResult);
50+
}
51+
}

0 commit comments

Comments
 (0)