so simply put, this is what I am trying to do:
I have a collection of Range
objects that are contiguous (non overlapping, with no gaps between them), each containing a start
and end
int, and a reference to another object obj
. These ranges are not of a fixed size (the first could be 1-49, the second 50-221, etc.). This collection could grow to be quite large.
I am hoping to find a way to look up the range (or more specifically, the object that it references) that includes a given number without having to iterate over the entire collection checking each range to see if it includes the number. These lookups will be performed frequently, so speed/performance is key.
Does anyone know of an algorithm/equation that might help me out here? I am writing in Java. I can provide more details if needed, but I figured I would try to keep it simple.
Thanks.
If sounds like you want to use a TreeMap
, where the key is the bottom of the range, and the value is the Range
object.
Then to identify the correct range, just use the floorEntry()
method to very quickly get the closest (lesser or equal) Range
, which should contain the key, like so:
TreeMap<Integer, Range> map = new TreeMap<>();
map.put(1, new Range(1, 10));
map.put(11, new Range(11, 30));
map.put(31, new Range(31, 100));
// int key = 0; // null
// int key = 1; // Range [start=1, end=10]
// int key = 11; // Range [start=11, end=30]
// int key = 21; // Range [start=11, end=30]
// int key = 31; // Range [start=31, end=100]
// int key = 41; // Range [start=31, end=100]
int key = 101; // Range [start=31, end=100]
// etc.
Range r = null;
Map.Entry<Integer, Range> m = map.floorEntry(key);
if (m != null) {
r = m.getValue();
}
System.out.println(r);
Since the tree is always sorted by the natural ordering of the bottom range boundary, all your searches will be at worst O(log(n)).
You'll want to add some sanity checking for when your key is completely out of bounds (for instance, when they key is beyond the end of the map, it returns the last Range
in the map), but this should give you an idea how to proceed.
Assuming that you lookups are of utmost importance, and you can spare O(N) memory and approximately O(N^2) preprocessing time, the algorithm would be:
ObjectsInRange
, which contains: start of range (int startOfRange
) and a set of objects (Set<Object> objects
)ArrayList<ObjectsInRange> oir
, which will contain ObjectsInRange
sorted by the startOfRange
Range r
, ensure that there exist ObjectsInRange
(let's call them a
and b
) such that a.startOfRange = r.start
and b.startOfRange = b.end
. Then, for all ObjectsInRange x
between a
, and until (but not including) b
, add r.obj
to their x.objects
setThe lookup, then, is as follows:
x
, find such i
that oir[i].startOfRange <= x
and oir[i+1].startOfRange > x
i
can be found with bisection in O(log N) time!oir[i].objects
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