C++ 存储一组非重叠范围,并查找值是否存在于任何一个范围中

C++ 存储一组非重叠范围,并查找值是否存在于任何一个范围中,c++,algorithm,search,binary-tree,range,C++,Algorithm,Search,Binary Tree,Range,我有一套范围: 范围1---(0-10) 范围2---(15-25) 范围3---(100-1000)和同样的。 我希望只存储边界,因为存储大范围将是有效的 现在我需要搜索一个数字,比如14。在这种情况下,14不存在于任何范围中,而(例如数字)16存在于其中一个范围中 我需要一个函数 bool search(ranges, searchvalue) { if searchvalues present in any of the ranges return true;

我有一套范围:

范围1---(0-10)

范围2---(15-25)

范围3---(100-1000)和同样的。 我希望只存储边界,因为存储大范围将是有效的

现在我需要搜索一个数字,比如14。在这种情况下,14不存在于任何范围中,而(例如数字)16存在于其中一个范围中

我需要一个函数

bool search(ranges, searchvalue)
{
    if searchvalues present in any of the ranges
        return true;
    else
        return false;
}

如何才能做到最好?这是严格不重叠的,重要的标准是搜索必须是最有效的。

因为范围不重叠,所以只需在符合值的范围内执行搜索。如果这些值在范围内排序,搜索就更简单了。是对搜索算法的总结


关于C++,你也可以使用STL,甚至可以使用容器提供的函数。g<代码>设置::如果有范围ri=[ai,bi],则查找

。您可以对所有
ai
进行排序,并将它们放入一个数组中,然后使用二进制搜索搜索
x>=ai和ai最小值的
x


找到此元素后,您必须检查
x是否可以根据
std::map
std::map::upper_bound
将某些内容组合在一起:

假设你有

std::map<int,int> ranges; // key is start of range, value is end of range
std::映射范围;//键是范围的开始,值是范围的结束
您可以执行以下操作:

bool search(const std::map<int,int>& ranges, int searchvalue)
{
    auto p = ranges.upper_bound(searchvalue); 
      // p->first > searchvalue
    if(p == ranges.begin())
        return false;
    --p;  // p->first <= searchvalue
    return searchvalue >= p->first && searchvalue <= p->second;
}
bool搜索(const std::map&ranges,int searchvalue)
{
自动p=范围。上限(搜索值);
//p->first>searchvalue
如果(p==ranges.begin())
返回false;
--p、 //p->first=p->first&&searchvalue second;
}
我使用的是C++11,如果使用的是C++03,则需要用适当的迭代器类型替换“auto”


编辑:将range()中的伪代码替换为return语句中的显式表达式。

因此,假设范围是连续的(即范围[1001000]包含100到1000之间的所有数字):

#包括
#包括
#包括
布尔值在范围内(标准::映射范围,int值)
{
返回
std::find_if(ranges.begin(),ranges.end(),
[&](标准::对)
{

返回值>=配对。第一和&值

一种可能性是将范围表示为一对值,并定义一个合适的比较函数。如果它的边界较小且没有重叠,则下面应该考虑一个范围小于另一个范围。作为副作用,此比较函数不允许在集合中存储重叠范围。> 要查找整数

n
,可以将其视为范围
[n,n]

#include <set>
#include <iostream>

typedef std::pair<int, int> Range;
struct RangeCompare
{
    //overlapping ranges are considered equivalent
    bool operator()(const Range& lhv, const Range& rhv) const
    {   
        return lhv.second < rhv.first;
    } 
};

bool in_range(const std::set<Range, RangeCompare>& ranges, int value)
{
    return ranges.find(Range(value, value)) != ranges.end();
}

int main()
{
    std::set<Range, RangeCompare> ranges;
    ranges.insert(Range(0, 10));
    ranges.insert(Range(15, 25));
    ranges.insert(Range(100, 1000));
    std::cout << in_range(ranges, 14) << ' ' << in_range(ranges, 16) << '\n';
}
#包括
#包括
typedef std::对范围;
结构范围比较
{
//重叠范围被认为是等效的
布尔运算符()
{   
返回lhv.secondstd::cout处理这个问题的标准方法是通过所谓的方法。基本上,你用额外的信息扩充一个普通的红黑树,这样每个节点x包含一个区间x.int,x的键是区间的低端x.int.low。每个节点x还包含一个值x.max,它是任何区间端点的最大值nt存储在以x为根的子树中。现在,您可以确定给定间隔x.int的x.max和节点x的子节点的最大值,如下所示:

x、 max=max(x.int.high,x.left.max,x.right.max)

这意味着,对于n个间隔,插入和删除在O(lg n)时间内运行。事实上,在O(1)时间内旋转后,可以更新max属性。下面是如何在间隔树T中搜索元素i

INTERVAL-SEARCH(T, i)
x = T:root
while x is different from T.nil and i does not overlap x.int
   if x.left is different from T.nil and x.left.max is greater than or equal to i.low 
      x = x.left
  else 
      x = x.right 
return x
搜索过程的复杂性也是O(lgn)。
要了解原因,请参阅CLRS,第14章(增强数据结构)。

一个好的解决方案可以如下所示

一个关键条件是范围不重叠

#include <set>
#include <iostream>
#include <assert.h>

template <typename T> struct z_range
{
        T s , e ;
        z_range ( T const & s,T const & e ) : s(s<=e?s:e), e(s<=e?e:s)
        {
        }
};

template <typename T> bool operator < (z_range<T> const & x , z_range<T> const & y )
{
    if ( x.e<y.s)
        return true ;
    return false ;
}

int main(int , char *[])
{
    std::set<z_range<int> > x;
    x.insert(z_range<int>(20,10));
    x.insert(z_range<int>(30,40));
    x.insert(z_range<int>(5,9));
    x.insert(z_range<int>(45,55));

    if (x.find(z_range<int>(15,15)) != x.end() )
        std::cout << "I have it" << std::endl ;
    else
        std::cout << "not exists" << std::endl ;

}
#包括
#包括
#包括
模板结构z_范围
{
ts,e;

z_范围(T常数和s,T常数和e):s(为了使用set::find之类的东西,我必须存储集合中范围的所有元素,而我只想存储所有范围的起点和终点,若有较大的范围,这会更好。好的,但你们说过一个值可以存在或不存在,那个么这个值存储在哪里呢?我只存储范围的边界那么“在这种情况下,14不存在于任何范围中,而(比如数字)16存在于其中一个范围中”是什么意思呢?我的意思是当我搜索14时,它不在任何范围内,而16在其中一个范围内。这意味着在该范围内有两次搜索。难道没有一种简化的方法和更快的方法可以做到这一点吗。@Dumb:在你的问题中,你没有提到你只有边界。不,你可以一次完成。只需存储
bi
例如,在
ai
附近使用struct@jrok我编辑了它。谢谢。我不认为它会被误解。duedl0r,我会尝试看看它的效率有多高。每毫秒都非常重要,我想确保这是最好的方式。inrange()是什么意思@Dumb我只是懒得拼出
searchvalue>=p->first&&searchvalue second
searchvalue>=p->first&&searchvaluesecond
,这取决于你的偏好。我认为这将作为正确的伪代码传递。搜索的顺序是什么?@Dumb时间复杂度是O(logn)完美。我会调整它以符合我的要求。在我看来,这是一个真正的选择。它的性能会如何
#include <set>
#include <iostream>

typedef std::pair<int, int> Range;
struct RangeCompare
{
    //overlapping ranges are considered equivalent
    bool operator()(const Range& lhv, const Range& rhv) const
    {   
        return lhv.second < rhv.first;
    } 
};

bool in_range(const std::set<Range, RangeCompare>& ranges, int value)
{
    return ranges.find(Range(value, value)) != ranges.end();
}

int main()
{
    std::set<Range, RangeCompare> ranges;
    ranges.insert(Range(0, 10));
    ranges.insert(Range(15, 25));
    ranges.insert(Range(100, 1000));
    std::cout << in_range(ranges, 14) << ' ' << in_range(ranges, 16) << '\n';
}
INTERVAL-SEARCH(T, i)
x = T:root
while x is different from T.nil and i does not overlap x.int
   if x.left is different from T.nil and x.left.max is greater than or equal to i.low 
      x = x.left
  else 
      x = x.right 
return x
#include <set>
#include <iostream>
#include <assert.h>

template <typename T> struct z_range
{
        T s , e ;
        z_range ( T const & s,T const & e ) : s(s<=e?s:e), e(s<=e?e:s)
        {
        }
};

template <typename T> bool operator < (z_range<T> const & x , z_range<T> const & y )
{
    if ( x.e<y.s)
        return true ;
    return false ;
}

int main(int , char *[])
{
    std::set<z_range<int> > x;
    x.insert(z_range<int>(20,10));
    x.insert(z_range<int>(30,40));
    x.insert(z_range<int>(5,9));
    x.insert(z_range<int>(45,55));

    if (x.find(z_range<int>(15,15)) != x.end() )
        std::cout << "I have it" << std::endl ;
    else
        std::cout << "not exists" << std::endl ;

}