C 确定一个范围是否包含在一组范围内

C 确定一个范围是否包含在一组范围内,c,C,我在一个数组中有一组范围。例如(但请注意,我的范围集将大于此值): 数据不必排序,类型都将是整数类型。此外,地址永远不会是负数,因此可以是uint32\u t 然后,我想通过以下函数查询是否会在所有这些范围的并集中包含另一个范围: bool isEncapsulated(uint32_t addr, size_t len){ // Here I need some sort of algorithm to determine whether // it is fully enc

我在一个数组中有一组范围。例如(但请注意,我的范围集将大于此值):

数据不必排序,类型都将是整数类型。此外,地址永远不会是负数,因此可以是
uint32\u t

然后,我想通过以下函数查询是否会在所有这些范围的并集中包含另一个范围:

bool isEncapsulated(uint32_t addr, size_t len){
    // Here I need some sort of algorithm to determine whether 
    // it is fully encapsulated. 
}
我面临的主要困难是找到一种方法来解释这样一个事实,即所提供的范围可能会超出两个定义范围的边界。例如,如果
start\u addr=170,长度=10
,则它位于两个定义范围的边界上

有没有一种优雅的方式来实现这一点

编辑:


我试图做的图形描述。基本上,范围1、2、3是我将在数组中定义的。然后,我将询问是否有任何范围A-F封装在其中。所以,只有D和E不是。我不仅仅希望重叠,我希望范围完全包含在预定义的范围内

如果没有太多的时间间隔,而您只想在不考虑算法的情况下完成任务,只需在
O(n)
中线性搜索数组即可。如果列表中的间隔不重叠,请对它们进行排序并使用(
O(log n)
)。如果它们重叠,通常选择的是数据结构(同样是
O(logn)
),但是合并重叠或相邻的间隔并进行二进制搜索会更简单

如果您的地址是非常小的整数,并且
O(logn)
对您来说太慢了(等等,什么?),您可以使用一个填充了所有已用地址的数组来交换一堆空间,以获得问题的
O(1)
答案,但您不太可能需要走这条路


您可以在预处理过程中合并相邻范围(即先创建并集),也可以只处理这种特殊情况。

如果间隔不多,您只想在不考虑算法的情况下完成任务,只需在
O(n)
中线性搜索数组即可。如果列表中的间隔不重叠,请对它们进行排序并使用(
O(log n)
)。如果它们重叠,通常选择的是数据结构(同样是
O(logn)
),但是合并重叠或相邻的间隔并进行二进制搜索会更简单

如果您的地址是非常小的整数,并且
O(logn)
对您来说太慢了(等等,什么?),您可以使用一个填充了所有已用地址的数组来交换一堆空间,以获得问题的
O(1)
答案,但您不太可能需要走这条路

您可以在预处理过程中合并相邻范围(即先创建并集),也可以只处理这种特殊情况

我遇到的主要困难是找到一种方法来解释这样一个事实,即所提供的范围可能会超出两个定义范围的边界

情况更糟。一个范围可能会超过许多定义的范围,顺序是询问可能会分割剩下的匹配项。考虑下面的代码,<代码> x>代码>范围首先在<代码> < < /代码>中找到。稍后,
x
的左部分需要匹配
b
,右部分需要匹配
c

Range:      xxxxxxxxxxxx
Def range 1 ___aaaaaa___
Def range 2 bbb_________
Def range 3 _________ccc
一些简单测试的代码。主要思想是在范围
addr/len
中获取左右地址,并测试每个部分中的地址。如果只是简单地全部放在一边,请继续下一节。否则,请缩短
addr/len
。这可能分为两部分。然后继续下一节

typedef struct {
  int start_addr;
  size_t length;
} Section;

// Is point `a` in the section?
// return left:-1, right:1, else 0
static int LeftInRight(intmax_t a, const Section *sec) {
  if (a < sec->start_addr) return -1;
  if (a >= sec->start_addr + (intmax_t) sec->length) return 1;
  return 0;
}

bool isEncapsulated_helper(intmax_t addr, size_t len, const Section *sec, size_t n) {
  for (size_t i = 0; i<n; i++) {
    if (len == 0) return true;
    int LSide =  LeftInRight(addr, &sec[i]);
    if (LSide > 0) continue;  // all of addr/len is to the right of this section
    int RSide =  LeftInRight(addr + (intmax_t) (len - 1), &sec[i]);
    if (RSide < 0) continue;  // all of addr/len is to the left of this section

    if (LSide < 0) {
      // portion of addr/len is to the left of this section
      intmax_t Laddr = addr;
      size_t Llen = (size_t) (sec[i].start_addr - addr);
      if (!isEncapsulated_helper(Laddr, Llen, sec + 1, n-i-1)) {
        return false;
      }
    }
    if (RSide <= 0) return true;
    // portion of addr/len is to the right of this section, continue with that
    intmax_t Raddr = sec[i].start_addr + (intmax_t) sec[i].length;
    size_t Rlen = (size_t) (addr + (intmax_t) len - Raddr);
    addr = Raddr;
    len = Rlen;
  }
  return len == 0;
}
我遇到的主要困难是找到一种方法来解释这样一个事实,即所提供的范围可能会超出两个定义范围的边界

情况更糟。一个范围可能会超过许多定义的范围,顺序是询问可能会分割剩下的匹配项。考虑下面的代码,<代码> x>代码>范围首先在<代码> < < /代码>中找到。稍后,
x
的左部分需要匹配
b
,右部分需要匹配
c

Range:      xxxxxxxxxxxx
Def range 1 ___aaaaaa___
Def range 2 bbb_________
Def range 3 _________ccc
一些简单测试的代码。主要思想是在范围
addr/len
中获取左右地址,并测试每个部分中的地址。如果只是简单地全部放在一边,请继续下一节。否则,请缩短
addr/len
。这可能分为两部分。然后继续下一节

typedef struct {
  int start_addr;
  size_t length;
} Section;

// Is point `a` in the section?
// return left:-1, right:1, else 0
static int LeftInRight(intmax_t a, const Section *sec) {
  if (a < sec->start_addr) return -1;
  if (a >= sec->start_addr + (intmax_t) sec->length) return 1;
  return 0;
}

bool isEncapsulated_helper(intmax_t addr, size_t len, const Section *sec, size_t n) {
  for (size_t i = 0; i<n; i++) {
    if (len == 0) return true;
    int LSide =  LeftInRight(addr, &sec[i]);
    if (LSide > 0) continue;  // all of addr/len is to the right of this section
    int RSide =  LeftInRight(addr + (intmax_t) (len - 1), &sec[i]);
    if (RSide < 0) continue;  // all of addr/len is to the left of this section

    if (LSide < 0) {
      // portion of addr/len is to the left of this section
      intmax_t Laddr = addr;
      size_t Llen = (size_t) (sec[i].start_addr - addr);
      if (!isEncapsulated_helper(Laddr, Llen, sec + 1, n-i-1)) {
        return false;
      }
    }
    if (RSide <= 0) return true;
    // portion of addr/len is to the right of this section, continue with that
    intmax_t Raddr = sec[i].start_addr + (intmax_t) sec[i].length;
    size_t Rlen = (size_t) (addr + (intmax_t) len - Raddr);
    addr = Raddr;
    len = Rlen;
  }
  return len == 0;
}

这是“重叠间隔”算法或其变体。谷歌搜索。如果
addr
len
是相同的类型或至少是相同的符号,那么便携式答案会更容易。另外还有许多带有
int/size\u t
的角落案例。
arr
中的数据是按起始地址可靠排序的,还是仅在样本数据中碰巧排序的?数据中的任何范围是否重叠,或者即使某些范围相邻,它们是否都不相交?同样,样本数据暗示了“所有不相交”,但这可能会产生误导。这些类型是整数类型,所以我们不必处理浮点问题吗?这些问题的答案会严重影响可能的算法。@JonathanLeffler数据不必排序,类型都是整数类型。另外,地址永远不会是负数,因此可以是
uint32\u t
,我的坏。@chux
start\u addr=170,length=10
应该返回
true
,因为这两部分
.start\u addr=150。start_addr=175
将完全包含它。这是“重叠间隔”算法或其变体。谷歌搜索。如果
addr
len
是相同的类型或至少是相同的符号,那么便携式答案会更容易。除此之外,还有许多带有
int/size\u t
的角盒。
arr
中的数据可靠吗