Range 作为 map 的 Key
当自定义的数据作为 STL 的 map 的 Key 时,需要编写自定义比较函数。(通常是小于函数)该函数用来比较 Key 的排序先后关系。
如果函数返回 true ,说明 left 小于 right 。
但是如果返回 false ,那么 map 会交换参数并再次调用比较函数,如果返回 true ,说明 right 小于 left ,如果也返回 false ,那么说明 left 和 right 等价( equivalence )。
注意调用 map 的 find 时,使用的并非直观的 == 运算符。而是 !(left < right) && !(right < left) ,在自己编写比较函数时,这一点要特别注意。但是调用 algorithm 的 find 是,使用的是 == 运算符。
如果现在想以某个 Range 作为 Key ,那么该如何实现比较函数呢。(只要 key 的 Range 在 map 某个 Range 内就认为找到)
一. 如果 Range 是连续的。
比如 [0, 20) , [20, 100), [100, 200) 等等(使用的是前闭后开区间表示法),那么其实只要把 Range 的开始位置作为 Key 就可以了。 find 时,自己编写 find 函数就可以了。
find 的逻辑如下: iterator find ( map , key )
如果 iterator->key >= key && (iterator+1)->key < key ,那么就返回 iterator 。当然如果 iterator+1 == map.end() ,那么也返回 iterator 就好了。详细的不再描述。
二. 如果 Range 是不连续的。
但是,如果 Range 是不连续的,比如 [0, 10) , [20, 50), [100, 200) 等等,那么就有必要自己做一个数据类型作为 Key 了。并为该类型重载 < 运算符。当然不重载该运算符也可以,写一个小于函数对象,将该类型作为 map 的第三个模板参数也可以。
三. 如果将 Range 放在 vector 中,并调用 find 进行查找时,那么就需要重载 == 运算符。如果基于 Equivalence 的话,该运算符可以用 < 运算符来实现。如果是基于 equality 的话,就要严格比较 Range 的开始结束位置。当然不重载该运算符也可以,写一个比较函数对象,将该类型的一个对象作为 find_if 的第四个参数即可。
四. 示例代码如下:
typedef struct stRange
{
// [ nBegin, nEnd )
int nBegin;
int nEnd;
stRange( int nPos = 0 )
{
nBegin = nEnd = nPos ;
}
stRange( int nLeft , int nRight )
{
nBegin = nLeft ;
nEnd = nRight;
}
}stRange;
inline bool operator < ( const stRange & lh , const stRange & rh )
{
// [lh.nBegin, lh.nEnd), [rh.nBegin, rh.nEnd)
if ( lh.nBegin < rh.nBegin && lh.nEnd <= rh.nBegin)
{
return true ;
}
[rh.nBegin, rh.nEnd), [lh.nBegin, lh.nEnd)
//else if ( lh.nBegin >= rh.nEnd && lh.nEnd > rh.nEnd)
//{
// return false ;
//}
return false ;
}
// Equivalence-based
inline bool operator == (const stRange & lh , const stRange & rh )
{
return !(lh < rh) && !(rh < lh) ;
}
Equality-based
//inline bool operator == (const stRange & lh , const stRange & rh )
//{
// return (lh.nBegin == rh.nBegin) && (lh.nEnd == rh.nEnd) ;
//}
测试代码如下:
#include <map>
#include <vector>
#include <algorithm>
using std::map ;
using std::vector ;
void TestRange()
{
map< stRange , int > mr ;
mr[stRange(0,10)] = 1 ;
mr[stRange(10,20)] = 2 ;
mr[stRange(20,50)] = 5 ;
mr[stRange(50,100)] = 10 ;
mr[stRange(200,1000)] = 100 ;
mr[stRange(3000,10000)] = 1000 ;
mr[stRange(11111,22222)] = 2222 ;
ASSERT( mr[stRange(4)] == 1 ) ;
ASSERT( mr[stRange(10)] == 2 ) ;
ASSERT( mr[stRange(40)] == 5 ) ;
ASSERT( mr[stRange(99)] == 10 ) ;
ASSERT( mr.end() == mr.find(stRange(100)) ) ;
ASSERT( mr.end() == mr.find(stRange(150)) ) ;
ASSERT( mr[stRange(400)] == 100 ) ;
ASSERT( mr[stRange(4000)] == 1000 ) ;
ASSERT( mr.end() == mr.find(stRange(40000)) ) ;
// vector
vector<stRange > vr ;
vr.push_back(stRange(0,10)) ;
vr.push_back(stRange(10,20)) ;
vr.push_back(stRange(20,50)) ;
vr.push_back(stRange(50,100)) ;
vr.push_back(stRange(200,1000)) ;
vr.push_back(stRange(3000,10000)) ;
vr.push_back(stRange(11111,22222)) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(4) )->nBegin == 0 ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(10) )->nBegin == 10 ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(40) )->nBegin == 20 ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(99) )->nBegin == 50 ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(100) ) == vr.end() ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(150) ) == vr.end() ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(400) )->nBegin == 200 ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(4000) )->nBegin == 3000 ) ;
ASSERT ( std::find( vr.begin() , vr.end() , stRange(40000) ) == vr.end() ) ;
}
五. 备注:
当 map 的 key 有多个排序条件时(第一排序条件,第二排序条件),那么比较函数首先比较第一排序条件,在第一排序条件相同的条件比较第二排序条件。在第二排序条件相同的条件下比较第三排序条件,以此类推。
示例代码如下。
inline bool operator < ( const CompKey & lh , const CompKey & rh )
{
if ( lh.firstComp < rh.firstComp )
{
return true ;
}
else if ( lh.firstComp == rh.firstComp )
{
return lh.secondComp < rh.secondComp ;
}
return false ;
}