Skip to content

Commit ddd2479

Browse files
docs: add edge cases to BinarySearch documentation
1 parent 9cd54ee commit ddd2479

File tree

1 file changed

+131
-107
lines changed

1 file changed

+131
-107
lines changed

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

Lines changed: 131 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,38 @@
55
/**
66
* Binary Search Algorithm Implementation
77
*
8-
* <p>Binary search is one of the most efficient searching algorithms for finding a target element
9-
* in a SORTED array. It works by repeatedly dividing the search space in half, eliminating half of
10-
* the remaining elements in each step.
8+
* <p>
9+
* Binary search is one of the most efficient searching algorithms for finding a
10+
* target element in a SORTED array. It works by repeatedly dividing the search
11+
* space in half, eliminating half of the remaining elements in each step.
1112
*
12-
* <p>IMPORTANT: This algorithm ONLY works correctly if the input array is sorted in ascending
13-
* order.
13+
* <p>
14+
* IMPORTANT: This algorithm ONLY works correctly if the input array is sorted
15+
* in ascending order.
1416
*
15-
* <p>Algorithm Overview: 1. Start with the entire array (left = 0, right = array.length - 1) 2.
16-
* Calculate the middle index 3. Compare the middle element with the target: - If middle element
17-
* equals target: Found! Return the index - If middle element is less than target: Search the right
18-
* half - If middle element is greater than target: Search the left half 4. Repeat until element is
19-
* found or search space is exhausted
17+
* <p>
18+
* Algorithm Overview: 1. Start with the entire array (left = 0, right =
19+
* array.length - 1) 2. Calculate the middle index 3. Compare the middle element
20+
* with the target: - If middle element equals target: Found! Return the index -
21+
* If middle element is less than target: Search the right half - If middle
22+
* element is greater than target: Search the left half 4. Repeat until element
23+
* is found or search space is exhausted
2024
*
21-
* <p>Performance Analysis: - Best-case time complexity: O(1) - Element found at middle on first
22-
* try - Average-case time complexity: O(log n) - Most common scenario - Worst-case time
23-
* complexity: O(log n) - Element not found or at extreme end - Space complexity: O(1) - Only uses
24-
* a constant amount of extra space
25+
* <p>
26+
* Performance Analysis: - Best-case time complexity: O(1) - Element found at
27+
* middle on first try - Average-case time complexity: O(log n) - Most common
28+
* scenario - Worst-case time complexity: O(log n) - Element not found or at
29+
* extreme end - Space complexity: O(1) - Only uses a constant amount of extra
30+
* space
2531
*
26-
* <p>Example Walkthrough: Array: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] Target: 7
32+
* <p>
33+
* Example Walkthrough: Array: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] Target: 7
2734
*
28-
* <p>Step 1: left=0, right=9, mid=4, array[4]=9 (9 &gt; 7, search left half) Step 2: left=0,
29-
* right=3, mid=1, array[1]=3 (3 &lt; 7, search right half) Step 3: left=2, right=3, mid=2,
30-
* array[2]=5 (5 &lt; 7, search right half) Step 4: left=3, right=3, mid=3, array[3]=7 (Found!
31-
* Return index 3)
35+
* <p>
36+
* Step 1: left=0, right=9, mid=4, array[4]=9 (9 &gt; 7, search left half) Step
37+
* 2: left=0, right=3, mid=1, array[1]=3 (3 &lt; 7, search right half) Step 3:
38+
* left=2, right=3, mid=2, array[2]=5 (5 &lt; 7, search right half) Step 4:
39+
* left=3, right=3, mid=3, array[3]=7 (Found! Return index 3)
3240
*
3341
* @author Varun Upadhyay (https://github.com/varunu28)
3442
* @author Podshivalov Nikita (https://github.com/nikitap492)
@@ -37,98 +45,114 @@
3745
*/
3846
class BinarySearch implements SearchAlgorithm {
3947

40-
/**
41-
* Generic method to perform binary search on any comparable type. This is the main entry point
42-
* for binary search operations.
43-
*
44-
* <p>Example Usage:
45-
* <pre>
46-
* Integer[] numbers = {1, 3, 5, 7, 9, 11};
47-
* int result = new BinarySearch().find(numbers, 7);
48-
* // result will be 3 (index of element 7)
49-
*
50-
* int notFound = new BinarySearch().find(numbers, 4);
51-
* // notFound will be -1 (element 4 does not exist)
52-
* </pre>
53-
*
54-
* @param <T> The type of elements in the array (must be Comparable)
55-
* @param array The sorted array to search in (MUST be sorted in ascending order)
56-
* @param key The element to search for
57-
* @return The index of the key if found, -1 if not found or if array is null/empty
58-
*/
59-
@Override
60-
public <T extends Comparable<T>> int find(T[] array, T key) {
61-
// Handle edge case: null or empty array
62-
if (array == null || array.length == 0) {
63-
return -1;
64-
}
48+
/**
49+
* Generic method to perform binary search on any comparable type. This is the
50+
* main entry point for binary search operations.
51+
*
52+
* <p>
53+
* Example Usage:
54+
*
55+
* <pre>
56+
* Integer[] numbers = { 1, 3, 5, 7, 9, 11 };
57+
* int result = new BinarySearch().find(numbers, 7);
58+
* // result will be 3 (index of element 7)
59+
*
60+
* int notFound = new BinarySearch().find(numbers, 4);
61+
* // notFound will be -1 (element 4 does not exist)
62+
* </pre>
63+
*
64+
* @param <T> The type of elements in the array (must be Comparable)
65+
* @param array The sorted array to search in (MUST be sorted in ascending
66+
* order)
67+
* @param key The element to search for
68+
* @return The index of the key if found, -1 if not found or if array is
69+
* null/empty
70+
*
71+
* <p><strong>Edge Cases:</strong>
72+
* <ul>
73+
* <li>Null array → returns -1</li>
74+
* <li>Empty array → returns -1</li>
75+
* <li>Null key → returns -1</li>
76+
* <li>Element not found → returns -1</li>
77+
* <li>Single element array → works correctly</li>
78+
* <li>Duplicate elements → may return any one valid index</li>
79+
* </ul>
80+
*/
81+
@Override
82+
public <T extends Comparable<T>> int find(T[] array, T key) {
83+
// Handle edge case: null or empty array
84+
if (array == null || array.length == 0) {
85+
return -1;
86+
}
6587

66-
// Handle edge case: null key
67-
// Searching for null in an array of Comparables is undefined behavior
68-
// Return -1 to indicate not found rather than throwing NPE
69-
if (key == null) {
70-
return -1;
71-
}
88+
// Handle edge case: null key
89+
// Searching for null in an array of Comparables is undefined behavior
90+
// Return -1 to indicate not found rather than throwing NPE
91+
if (key == null) {
92+
return -1;
93+
}
7294

73-
// Delegate to the core search implementation
74-
return search(array, key, 0, array.length - 1);
75-
}
95+
// Delegate to the core search implementation
96+
return search(array, key, 0, array.length - 1);
97+
}
7698

77-
/**
78-
* Core recursive implementation of binary search algorithm. This method divides the problem
79-
* into smaller subproblems recursively.
80-
*
81-
* <p>How it works:
82-
* <ol>
83-
* <li>Calculate the middle index to avoid integer overflow</li>
84-
* <li>Check if middle element matches the target</li>
85-
* <li>If not, recursively search either left or right half</li>
86-
* <li>Base case: left &gt; right means element not found</li>
87-
* </ol>
88-
*
89-
* <p>Time Complexity: O(log n) because we halve the search space each time.
90-
* Space Complexity: O(log n) due to recursive call stack.
91-
*
92-
* @param <T> The type of elements (must be Comparable)
93-
* @param array The sorted array to search in
94-
* @param key The element we're looking for
95-
* @param left The leftmost index of current search range (inclusive)
96-
* @param right The rightmost index of current search range (inclusive)
97-
* @return The index where key is located, or -1 if not found
98-
*/
99-
private <T extends Comparable<T>> int search(T[] array, T key, int left, int right) {
100-
// Base case: Search space is exhausted
101-
// This happens when left pointer crosses right pointer
102-
if (right < left) {
103-
return -1; // Key not found in the array
104-
}
99+
/**
100+
* Core recursive implementation of binary search algorithm. This method divides
101+
* the problem into smaller subproblems recursively.
102+
*
103+
* <p>
104+
* How it works:
105+
* <ol>
106+
* <li>Calculate the middle index to avoid integer overflow</li>
107+
* <li>Check if middle element matches the target</li>
108+
* <li>If not, recursively search either left or right half</li>
109+
* <li>Base case: left &gt; right means element not found</li>
110+
* </ol>
111+
*
112+
* <p>
113+
* Time Complexity: O(log n) because we halve the search space each time. Space
114+
* Complexity: O(log n) due to recursive call stack.
115+
*
116+
* @param <T> The type of elements (must be Comparable)
117+
* @param array The sorted array to search in
118+
* @param key The element we're looking for
119+
* @param left The leftmost index of current search range (inclusive)
120+
* @param right The rightmost index of current search range (inclusive)
121+
* @return The index where key is located, or -1 if not found
122+
*/
123+
private <T extends Comparable<T>> int search(T[] array, T key, int left, int right) {
124+
// Base case: Search space is exhausted
125+
// This happens when left pointer crosses right pointer
126+
if (right < left) {
127+
return -1; // Key not found in the array
128+
}
105129

106-
// Calculate middle index
107-
// Using (left + right) / 2 could cause integer overflow for large arrays
108-
// So we use: left + (right - left) / 2 which is mathematically equivalent
109-
// but prevents overflow
110-
int median = (left + right) >>> 1; // Unsigned right shift is faster division by 2
130+
// Calculate middle index
131+
// Using (left + right) / 2 could cause integer overflow for large arrays
132+
// So we use: left + (right - left) / 2 which is mathematically equivalent
133+
// but prevents overflow
134+
int median = (left + right) >>> 1; // Unsigned right shift is faster division by 2
111135

112-
// Get the value at middle position for comparison
113-
int comp = key.compareTo(array[median]);
136+
// Get the value at middle position for comparison
137+
int comp = key.compareTo(array[median]);
114138

115-
// Case 1: Found the target element at middle position
116-
if (comp == 0) {
117-
return median; // Return the index where element was found
118-
}
119-
// Case 2: Target is smaller than middle element
120-
// This means if target exists, it must be in the LEFT half
121-
else if (comp < 0) {
122-
// Recursively search the left half
123-
// New search range: [left, median - 1]
124-
return search(array, key, left, median - 1);
125-
}
126-
// Case 3: Target is greater than middle element
127-
// This means if target exists, it must be in the RIGHT half
128-
else {
129-
// Recursively search the right half
130-
// New search range: [median + 1, right]
131-
return search(array, key, median + 1, right);
132-
}
133-
}
139+
// Case 1: Found the target element at middle position
140+
if (comp == 0) {
141+
return median; // Return the index where element was found
142+
}
143+
// Case 2: Target is smaller than middle element
144+
// This means if target exists, it must be in the LEFT half
145+
else if (comp < 0) {
146+
// Recursively search the left half
147+
// New search range: [left, median - 1]
148+
return search(array, key, left, median - 1);
149+
}
150+
// Case 3: Target is greater than middle element
151+
// This means if target exists, it must be in the RIGHT half
152+
else {
153+
// Recursively search the right half
154+
// New search range: [median + 1, right]
155+
return search(array, key, median + 1, right);
156+
}
157+
}
134158
}

0 commit comments

Comments
 (0)