Reputation: 655
I'm implementing binary search. The function returns the index of the target value when it's found in the array, otherwise -1
.
I prefer to deal with indices that are i32
rather than usize
as I need to allow negatives for returning -1
when the target is not found. I'm explicitly casting at the edges of the function, which I assume isn't great. What's a more Rusty way around this?
fn binary_search(nums: &[i32], target: i32) -> i32 {
let num_size: i32 = nums.len() as i32; // This seems bad
bsearch(nums, target, 0, num_size as usize)
}
fn bsearch(nums: &[i32], target: i32, lo: usize, hi: usize) -> i32 {
if hi < lo {
return -1;
}
let mid_idx = lo + ((hi - lo) / 2);
let guess = nums[mid_idx];
if guess > target {
bsearch(nums, target, lo, mid_idx - 1)
} else if guess < target {
bsearch(nums, target, mid_idx + 1, hi)
} else {
mid_idx as i32 // This seems bad
}
}
Upvotes: 0
Views: 86
Reputation: 59005
You're unnecessarily fighting the language. i32
isn't an appropriate type for array indices. Instead, you should use Option
:
fn binary_search(nums: &[i32], target: i32) -> Option<usize> {
let num_size = nums.len();
bsearch(nums, target, 0, num_size)
}
fn bsearch(nums: &[i32], target: i32, lo: usize, hi: usize) -> Option<usize> {
if hi < lo {
return None;
}
let mid_idx = lo + ((hi - lo) / 2);
let guess = nums[mid_idx];
if guess > target {
bsearch(nums, target, lo, mid_idx - 1)
} else if guess < target {
bsearch(nums, target, mid_idx + 1, hi)
} else {
Some(mid_idx)
}
}
Given that a function which deals with arrays has to use usize
for indices, there's no benefit in forcing it to use i32
instead. If you want i32
because you want "not found" to be -1
, you can perform the conversion after the function has finished.
Note: also, keep in mind that when using i32
, you really should do bounds checking. On 64-bit systems, array lengths can greatly exceed what an i32
can represent, and even on 32-bit machines, you run the risk of having negative array indices.
Upvotes: 7