Reading the BTreeSet
documentation, I can't seem to figure out how to get the least value greater than, or greatest value less than an element from a BTreeSet
in logarithmic time.
I see there is a range
method that can give the values in an arbitrary (min, max) range, but what if I don't know the range and I just want the previous and/or the next element in logarithmic time?
This would be similar to lower_bound
and upper_bound
in std::set
in C++.
Get the value of upper bound: int index = upper_bound(size, size+27, sum) - size; cout << size[index] << endl; I tested performance using the code below. Each one-line code under a for loop give the index where upper bound is.
Set lower_bound() function in C++ STL returns an iterator pointing to the element in the container which is equivalent to k passed in the parameter. If k is not present in the set container, then the function returns an iterator pointing to the immediate next element which is just greater than k.
The index of the first element of an array is called its lower bound, while the index of the last element is called its upper bound. By default, an array is indexed beginning with zero. The declaration must include the number of elements inside parentheses.
but what if I don't know the range
Then use an unbounded range:
use std::collections::BTreeSet;
fn neighbors(tree: &BTreeSet<i32>, val: i32) -> (Option<&i32>, Option<&i32>) {
use std::ops::Bound::*;
let mut before = tree.range((Unbounded, Excluded(val)));
let mut after = tree.range((Excluded(val), Unbounded));
(before.next_back(), after.next())
}
fn main() {
let tree: BTreeSet<_> = [1, 3, 5].iter().cloned().collect();
let (prev, next) = neighbors(&tree, 2);
println!("greatest less than 2: {:?}", prev);
println!("least bigger than 2: {:?}", next);
}
greatest less than 2: Some(1)
least bigger than 2: Some(3)
BTreeSet::range
returns a double-ended iterator, so you can pull from either side of it.
Note that we are using the very explicit Bound
operator so that we do not include the value we are looking around.
There have been discussions about enhancing BTreeMap
/ BTreeSet
to have a "cursor" API that might allow you to find an element and then "move around" inside the tree. This would allow you to avoid searching through the tree to find the start node twice, but it has not been implemented.
A pull request was opened to do so, but it was closed because it was deemed that there should be more discussion about how such an API should look and work.
Well... if you don't mind modifying the current collection and taking a performance hit... it appears that you can use split_off
creatively.
let mut tree = BTreeSet::new();
tree.insert(1);
tree.insert(3);
tree.insert(5);
let other = tree.split_off(&2);
println!("{:?}", tree);
println!("{:?}", other);
Will print {1}
and {3, 5}
:
Once you are done, you can reassemble the tree using tree.append(other)
.
And yes, it's really less than ideal...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With