rust二分搜索

阅读量: searchstar 2021-10-06 17:38:25
Categories: Tags:

如果要二分搜索某个特定值,可以用binary_search
https://doc.rust-lang.org/stable/std/primitive.slice.html#method.binary_search

如果要实现C++里的lower_bound和upper_bound类似的功能,可以用partition_point:
https://doc.rust-lang.org/stable/std/primitive.slice.html#method.partition_point

pub fn partition_point<P>(&self, pred: P) -> usize where
P: FnMut(&T) -> bool,

返回第一个使得pred返回false的元素的下标,与C++里的partition_point一样:
http://cplusplus.com/reference/algorithm/partition_point/?kw=partition_point

例子:

fn main() {
let a = [1, 2, 3, 3, 4];
// Lower bound
println!("{}", a.partition_point(|x| *x < 3));
// Upper bound
println!("{}", a.partition_point(|x| *x <= 3));
}
2
4

相关:Add lower_bound, upper_bound and equal_range for slices where T: Ord to complement binary_search

但是要注意的是,如果要搜索某个符合条件的值,那么不要用collect做一个Vec再用partition_point,因为rust(目前)并不会将这个构建Vec的过程优化掉,时间复杂度和空间复杂度都是O(n)。例子:

fn main() {
println!("{}", (0usize..2usize.pow(29)).collect::<Vec<usize>>().partition_point(|v| v < &233usize));
}

内存使用量会达到4GB。

自己写一个二分搜索就不存在这个问题了:

fn partition_point_addable<T, F>(mut start: T, mut end: T, pred: F) -> T
where
T: Copy
+ Add<T, Output = T>
+ Sub<T, Output = T>
+ PartialEq
+ One
+ Shr<i8, Output = T>,
F: Fn(&T) -> bool,
{
while start != end {
let mid = start + ((end - start) >> 1);
if pred(&mid) {
start = mid + T::one();
} else {
end = mid;
}
}
start
}