题目链接在:针对一群范围对的最快查找算法设计(不要用数组),是我目前遇到的一个较棘手的问题。
描述如下:
假如有一群范围对,格式为:<范围表示,该范围对应的结果值>,设计一个最快查找算法,使得给定一个值,输出该值所在范围对的结果值。
注意:范围对之间没有交集,即不可能存在<1, 10>和<2, 11>这样的两个范围对。
例如有以下几个范围对:
<<1, 2>, 20>
<<3, 37>, 27>
<<48, 57>, 28>
<<58, 63>, 27>
<<97, 128>, 122>
<<129, 149>, 12>
<<150, 189>, 13>
<<200, 245>, 14>
<<246, 256>, 129>
<<479, 560>, 12>假如给定一个数100,则根据题意应输出122,因为100属于范围对<97, 128>
要求:不要用范围对作为下标用数组来存储,因为范围对可能非常大。
对于这个问题,思考许久,有了下面几个思路
1. 用STL map来存储这些范围对(key)及对应的结果集(value),用map进行查找
范围对定义如下:
class range { public: int from; int to; public: range(): from(-1), to(-1) {} range(int f, int t): from(f), to(t) {} };
map定义为:
typedef map<range*, int> range_map;
但这里有个问题,map的key是自定义类型,一般需要自定义比较函数才能进行查找,一般的自定义比较函数如下:
struct cmp_func { bool operator()(const range* lc,const range* rc) const { return (lc->from < rc->from) || (lc->from == rc->from && lc->to < rc->to); } };
但这样的比较函数并不适用于我们的需求,因为我们要求查询的并不是一个范围对,即并不是查询map中有没有<3, 37>这样的范围对,而是要求给定一个值,查询这个值属于哪个范围对,那么能不能自定义一个这样的比较函数呢?以上面那个例子为例,如果我们查找35这个数,我们将35包装成一个范围对<35, 35>,然后查找它包含在map中的哪个范围对,上面的例子是包含在<3, 37>这样的范围对,这样就找到了,也就是两个key相等,只要它们包含在同一个范围对即可。这似乎有点奇怪,违背了通常意义上的比较含义(也就是两个key相等,两个key的组成部分都应该相同才是)。不管如何,这样的比较函数还是比较简单的,如下:
struct cmp_func { bool operator()(const range* lc,const range* rc) const { return lc->to < rc->from; } };
这样就实现了我们用map的find函数来查找给定的一个数属于哪个范围对了。当然,这时我们的map定义就变成了:
typedef map<range*, int, cmp_func> range_map;
用map查找表面上看上去应该挺高效的,至少比一个个顺序查找要快吧,但事实却并非如此。我用未自定义比较函数的map顺序查找和自定义上面比较函数的map find查找,结果却发现用自定义比较函数后的效果并不好,竟然比顺序查找还要慢,下面的粗糙的测试程序:
#include<iostream> #include<stdio.h> #include<map> #include<sys/time.h> using namespace std; class range { public: int from;