std::map lower_bound is not returning the correct value
Good afternoon,开发者_如何学Python I am trying to use the std::map lower_found member function. However , it keeps returning the wrong answer. Here is an excerpt of my test code. Please explain to me how to make std::map lower bound function properly. Thank you.
class Interval {
public:
explicit Interval(int item){
mLow = item;
mHigh = item;
mStamp = 0;
}
Interval(int low, int high, int stamp = 0){
mLow = low;
mHigh = high;
mStamp = stamp;
}
Interval(void){
mLow = 0;
mHigh = 0;
mStamp = 0;
}
Interval(const Interval& r):
mLow(r.mLow),
mHigh(r.mHigh),
mStamp(r.mStamp)
{
}
bool operator<(const Interval& rhs) const{
if (mLow < rhs.mLow){
return true;
}
return false;
} // operator<
int low() const { return mLow; }
int high() const { return mHigh; }
int getStamp() const { return mStamp; }
void setLow(int lower) { mLow = lower; }
void setHigh(int higher) { mHigh = higher; }
void setStamp(int stamp) { mStamp = stamp; }
private:
int mLow;
int mHigh;
int mStamp;
}; // class Interval
int main(int Argc_,char *Argv_[]) {
int n;
Interval r;
std::map<Interval, Interval> Intervals_type;
r.setLow(0);
r.setHigh(10);
r.setStamp(1);
std::pair< Interval, Interval > tmp(r,r);
Intervals_type.insert(tmp);
r.setLow(10);
r.setHigh(20);
r.setStamp(2);
std::pair< Interval, Interval > tmp2(r,r);
Intervals_type.insert(tmp2);
r.setLow(20);
r.setHigh(30);
r.setStamp(3);
std::pair< Interval, Interval > tmp3(r,r);
Intervals_type.insert(tmp3);
r.setLow(30);
r.setHigh(40);
r.setStamp(4);
std::pair< Interval, Interval > tmp4(r,r);
Intervals_type.insert(tmp4);
n = 36;
std::map<Interval, Interval>::const_iterator it =
Intervals_type.lower_bound(Interval(n));
if (it == Intervals_type.end()){
printf(" n = %d not found\n",n);
}
return 1;
}
std::map
compares with operator <
only, so it knows only about Interval::mLow
, effectively treating all intervals as [mLow, ∞). You're using the wrong container. It's possible to do it with map but it's harder. Use Boost.Icl instead.
Edit: The best thing you have in STL for this purpose is std::multi_set. Order your intervals by the right end-point:
bool operator<(const Interval& rhs) const{
return mHigh < rhs.mHigh;
}
Now you can do it this way:
std::multi_set<Interval> cont;
cont.insert(Interval(0,10,1));
cont.insert(Interval(10,20,2));
cont.insert(Interval(20,30,3));
cont.insert(Interval(30,40,4));
std::multi_set<Interval>::const_iterator iter = cont.lower_bound(Interval(36));
if(iter == cont.end() || iter->low() > 36)
// not found
else
// found
IIUC, you're dealing with ranges, and you have an invariant on the map that ranges don't overlap. If that's the case, you have to define your operator< so that it deals with ranges, and does something drastic (assertion failure or an exception) in the case of an overlap, to prevent such ranges from being inserted. Assuming a half open range of [low,high) and an assertion that high >= low in the constructor of Interval, something like the following should work:
struct CmpInterval
{
// For insertion...
bool operator<( Interval const& lhs, Interval const& rhs) const
{
assert( lhs.low >= rhs.high
|| lhs.high <= rhs.low
|| (lhs.low == rhs.low && lhs.high == rhs.high) );
return lhs.low < rhs.low;
}
// For find, lower_bound, etc.
bool operator<( Interval const& lhs, int target ) const
{
return lhs.low < target;
}
bool operator<( int target, Interval const& rhs ) const
{
return target <= rhs.high;
}
};
The last two are used for lower_bound, find, etc., when you pass a simple integer as key (and not an Interval); together, they define a strict ordering relationship between an int and an Inteval, IFF there are no overlapping intervals, and an equivalence relationship such that all n in an interval [i, j) are equivalent to that range and to each other. (Again, if there are overlapping intervals, there is no equivalence relationship, and the behavior is undefined.)
lower_bound should return the position before the first item that is equal or larger. The largest item in your map is actually smaller so end is returned.
In your operator < you only check mLow. If you want to check that 36 is in the range 30 to 40 then correct your operator <.
The definition of lower_bound
is that it returns a location where you could insert the item and still keep the container sorted. Your comparison function only works with the low
member; your container has the contents 0,10,20,30 for the lows. The only insertion point for 36 that keeps the container sorted is at the very end.
精彩评论